@rubytech/create-maxy-code 0.1.409 → 0.1.410

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 (22) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/scheduling/PLUGIN.md +2 -2
  3. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/agent-dispatch-manager-grounding.test.js +5 -5
  4. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/agent-dispatch-manager-grounding.test.js.map +1 -1
  5. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch.test.js +103 -34
  6. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/agent-dispatch.test.js.map +1 -1
  7. package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.d.ts +45 -11
  8. package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.d.ts.map +1 -1
  9. package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.js +74 -23
  10. package/payload/platform/plugins/scheduling/mcp/dist/lib/agent-dispatch.js.map +1 -1
  11. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/standing-audit.test.js +48 -9
  12. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/standing-audit.test.js.map +1 -1
  13. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +9 -5
  14. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
  15. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +53 -18
  16. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
  17. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-event-agent.test.js +24 -4
  18. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-event-agent.test.js.map +1 -1
  19. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-agent.test.js +6 -4
  20. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-update-agent.test.js.map +1 -1
  21. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +2 -0
  22. package/payload/server/server.js +22 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.409",
3
+ "version": "0.1.410",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"
@@ -124,14 +124,14 @@ An `action` invokes one pre-encoded MCP tool with no reasoning. When a due event
124
124
  ```
125
125
 
126
126
  - `channel` — `whatsapp` or `telegram`.
127
- - `destination` — the E.164 phone (WhatsApp) or chat id (Telegram) to run the turn for and reply to. It **must already be a registered admin or account-manager** on that channel; a destination that is not is rejected when the event is created.
127
+ - `destination` — the E.164 phone (WhatsApp) or chat id (Telegram) to run the turn for and reply to. It **must already be a registered admin or account-manager** on that channel; a destination that is not is rejected when the event is created. For WhatsApp the authoritative admin/manager lists are read from the socket-owning **house** account (never the event's own account), and the destination's registered account must match the account that created the schedule: an admin belongs to the house, a manager to its bound sub-account. The house/owner account may target any registered admin or manager; a sub-account is locked to its own manager(s). A refusal names the true reason — `not-registered` (in no house list) or `cross-account` (registered to a different account, naming both accounts).
128
128
  - `prompt` — the instruction the agent runs.
129
129
 
130
130
  An event carries **either** an `action` **or** an `agentDispatch`, never both — setting one clears the other. Agent dispatch is stored as `agentChannel`, `agentDestination`, `agentPrompt`. Use `schedule-update` with `agentDispatch` to modify or `agentDispatch: null` to clear. On WhatsApp, a destination bound as an account-manager scopes the spawned session to its sub-account; on Telegram the session runs on the house account.
131
131
 
132
132
  A WhatsApp `agentDispatch` destination may therefore be an account manager, not only an admin phone — this is the supported way to send a manager a proactive or scheduled WhatsApp message. The reply is delivered over the house's paired line regardless of which sub-account the session is scoped to; socket ownership never restricts which number the dispatch can reach.
133
133
 
134
- Dispatch results are recorded on the Event node (`lastDispatchResult`, `lastDispatchAt`) exactly as for tool actions. Every heartbeat tick also audits stored agent dispatches and logs `[schedule-audit] op=stale-dispatch` for any whose destination has stopped being an admin or whose bound sub-account is gone, so a binding that rots between scheduling and firing is surfaced before it mis-dispatches.
134
+ Dispatch results are recorded on the Event node (`lastDispatchResult`, `lastDispatchAt`) exactly as for tool actions. Every heartbeat tick also audits stored agent dispatches against the same house-authority rule used at creation, and logs `[schedule-audit] op=stale-dispatch` with the identical reason codes — `not-registered` (destination left the house lists), `cross-account` (rebound to a different account than the one that created the schedule), or `sub-account-missing` (bound sub-account deleted) so a binding that rots between scheduling and firing is surfaced with its true cause before it mis-dispatches.
135
135
 
136
136
  ## Reconciling public bookings (D1 → graph)
137
137
 
@@ -1,9 +1,9 @@
1
1
  // Task 1435 — content-presence gate for the scheduling side of the WhatsApp
2
- // deliverability grounding. `isValidAgentDestination` accepts an account
3
- // manager (adminPhones OR accountManagers), so scheduled dispatch is the
4
- // supported way to reach a manager. PLUGIN.md must say so plainly, and deliver-
5
- // over-the-house-line must be stated, so the agent cites it instead of inventing
6
- // a line-ownership restriction. Mirrors time-resolve-description.test.ts.
2
+ // deliverability grounding. `validateAgentDestination` accepts an account
3
+ // manager (the house's adminPhones OR accountManagers), so scheduled dispatch is
4
+ // the supported way to reach a manager. PLUGIN.md must say so plainly, and
5
+ // deliver-over-the-house-line must be stated, so the agent cites it instead of
6
+ // inventing a line-ownership restriction. Mirrors time-resolve-description.test.ts.
7
7
  import { describe, it, expect } from "vitest";
8
8
  import { readFileSync } from "fs";
9
9
  import { resolve } from "path";
@@ -1 +1 @@
1
- {"version":3,"file":"agent-dispatch-manager-grounding.test.js","sourceRoot":"","sources":["../../src/__tests__/agent-dispatch-manager-grounding.test.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,yEAAyE;AACzE,yEAAyE;AACzE,gFAAgF;AAChF,iFAAiF;AACjF,0EAA0E;AAC1E,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC,CAAC;AAE9E,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;IACxD,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,4EAA4E,CAC7E,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,sEAAsE,CACvE,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"agent-dispatch-manager-grounding.test.js","sourceRoot":"","sources":["../../src/__tests__/agent-dispatch-manager-grounding.test.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,0EAA0E;AAC1E,iFAAiF;AACjF,2EAA2E;AAC3E,+EAA+E;AAC/E,oFAAoF;AACpF,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC,CAAC;AAE9E,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;IACxD,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,4EAA4E,CAC7E,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CACtB,sEAAsE,CACvE,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,10 +1,27 @@
1
1
  import { describe, it, expect, afterEach } from "vitest";
2
- import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { mkdtempSync, rmSync, mkdirSync, writeFileSync } from "node:fs";
3
3
  import { tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
- import { normalizeE164, phonesMatch, isValidAgentDestination, boundSubAccountFor, } from "../agent-dispatch.js";
6
- function makeAccountDir(config) {
5
+ import { normalizeE164, phonesMatch, validateAgentDestination, boundSubAccountFor, } from "../agent-dispatch.js";
6
+ // The house-authority validator resolves the socket-owning house from the
7
+ // PARENT accounts dir (via account-enumeration), so fixtures must use
8
+ // UUID-named account dirs carrying role:"house" (the resolver's contract).
9
+ const HOUSE = "11111111-1111-4111-8111-111111111111";
10
+ const SUB_A = "22222222-2222-4222-8222-222222222222";
11
+ const SUB_B = "33333333-3333-4333-8333-333333333333";
12
+ function makeAccountsDir(seed) {
7
13
  const dir = mkdtempSync(join(tmpdir(), "agent-dispatch-"));
14
+ seed(dir);
15
+ return dir;
16
+ }
17
+ function seedAccount(accountsDir, id, cfg) {
18
+ const d = join(accountsDir, id);
19
+ mkdirSync(d, { recursive: true });
20
+ writeFileSync(join(d, "account.json"), JSON.stringify(cfg), "utf-8");
21
+ }
22
+ // A single account dir (for the direct-read helpers boundSubAccountFor tests).
23
+ function makeAccountDir(config) {
24
+ const dir = mkdtempSync(join(tmpdir(), "agent-dispatch-one-"));
8
25
  writeFileSync(join(dir, "account.json"), JSON.stringify(config), "utf-8");
9
26
  return dir;
10
27
  }
@@ -23,62 +40,114 @@ describe("normalizeE164 / phonesMatch (replica of platform normalize.ts)", () =>
23
40
  expect(phonesMatch("", "")).toBe(false);
24
41
  });
25
42
  });
26
- describe("isValidAgentDestination — whatsapp", () => {
43
+ describe("validateAgentDestination — whatsapp house-authority + creating-account match", () => {
27
44
  let dirs = [];
28
45
  afterEach(() => {
29
46
  for (const d of dirs)
30
47
  rmSync(d, { recursive: true, force: true });
31
48
  dirs = [];
32
49
  });
33
- it("accepts a destination present in adminPhones (phonesMatch)", () => {
34
- const dir = makeAccountDir({ whatsapp: { adminPhones: ["+447504472444"] } });
35
- dirs.push(dir);
36
- // spaced form must still match the stored bare form
37
- expect(isValidAgentDestination(dir, "whatsapp", "+44 7504 472444")).toEqual({ valid: true });
50
+ it("house-created dispatch to a house admin is valid (spaced form matches stored bare form)", () => {
51
+ const acc = makeAccountsDir((a) => seedAccount(a, HOUSE, { role: "house", whatsapp: { adminPhones: ["+447504472444"] } }));
52
+ dirs.push(acc);
53
+ expect(validateAgentDestination(acc, HOUSE, "whatsapp", "+44 7504 472444")).toEqual({ valid: true });
38
54
  });
39
- it("accepts a destination that is an accountManagers key", () => {
40
- const dir = makeAccountDir({
41
- whatsapp: { adminPhones: [], accountManagers: { "447504472444": "sub-abc" } },
55
+ it("sub-account-created dispatch to its own manager is valid", () => {
56
+ const acc = makeAccountsDir((a) => {
57
+ seedAccount(a, HOUSE, { role: "house", whatsapp: { accountManagers: { "447958391734": SUB_A } } });
58
+ seedAccount(a, SUB_A, {});
42
59
  });
43
- dirs.push(dir);
44
- expect(isValidAgentDestination(dir, "whatsapp", "+447504472444")).toEqual({ valid: true });
60
+ dirs.push(acc);
61
+ expect(validateAgentDestination(acc, SUB_A, "whatsapp", "+44 7958 391734")).toEqual({ valid: true });
45
62
  });
46
- it("rejects a destination absent from both lists", () => {
47
- const dir = makeAccountDir({ whatsapp: { adminPhones: ["+447504472444"] } });
48
- dirs.push(dir);
49
- expect(isValidAgentDestination(dir, "whatsapp", "+447999999999")).toEqual({
63
+ it("sub-account-created dispatch to ANOTHER sub-account's manager is cross-account", () => {
64
+ const acc = makeAccountsDir((a) => {
65
+ seedAccount(a, HOUSE, { role: "house", whatsapp: { accountManagers: { "447958391734": SUB_A } } });
66
+ seedAccount(a, SUB_A, {});
67
+ seedAccount(a, SUB_B, {});
68
+ });
69
+ dirs.push(acc);
70
+ expect(validateAgentDestination(acc, SUB_B, "whatsapp", "+447958391734")).toEqual({
50
71
  valid: false,
51
- reason: "destination-not-admin",
72
+ reason: "cross-account",
73
+ destinationAccount: SUB_A,
74
+ scheduleAccount: SUB_B,
52
75
  });
53
76
  });
54
- it("rejects when there is no whatsapp config at all", () => {
55
- const dir = makeAccountDir({});
56
- dirs.push(dir);
57
- expect(isValidAgentDestination(dir, "whatsapp", "+447504472444").valid).toBe(false);
77
+ it("sub-account-created dispatch to a house admin is cross-account (sub locked to own managers)", () => {
78
+ const acc = makeAccountsDir((a) => {
79
+ seedAccount(a, HOUSE, { role: "house", whatsapp: { adminPhones: ["+447504472444"] } });
80
+ seedAccount(a, SUB_A, {});
81
+ });
82
+ dirs.push(acc);
83
+ expect(validateAgentDestination(acc, SUB_A, "whatsapp", "+447504472444")).toEqual({
84
+ valid: false,
85
+ reason: "cross-account",
86
+ destinationAccount: HOUSE,
87
+ scheduleAccount: SUB_A,
88
+ });
89
+ });
90
+ it("house-created dispatch to any sub-account manager is valid (owner exception)", () => {
91
+ const acc = makeAccountsDir((a) => {
92
+ seedAccount(a, HOUSE, { role: "house", whatsapp: { accountManagers: { "447958391734": SUB_A } } });
93
+ seedAccount(a, SUB_A, {});
94
+ });
95
+ dirs.push(acc);
96
+ expect(validateAgentDestination(acc, HOUSE, "whatsapp", "+447958391734")).toEqual({ valid: true });
97
+ });
98
+ it("unregistered number is not-registered", () => {
99
+ const acc = makeAccountsDir((a) => seedAccount(a, HOUSE, { role: "house", whatsapp: { adminPhones: ["+447504472444"] } }));
100
+ dirs.push(acc);
101
+ expect(validateAgentDestination(acc, HOUSE, "whatsapp", "+447999999999")).toEqual({
102
+ valid: false,
103
+ reason: "not-registered",
104
+ });
105
+ });
106
+ it("reads the HOUSE list, not the creating sub-account's own account.json (the 1439 bug)", () => {
107
+ // The manager map lives ONLY on the house; the sub-account carries none.
108
+ // Pre-fix this read the sub-account and returned not-registered.
109
+ const acc = makeAccountsDir((a) => {
110
+ seedAccount(a, HOUSE, { role: "house", whatsapp: { accountManagers: { "447958391734": SUB_A } } });
111
+ seedAccount(a, SUB_A, { whatsapp: {} });
112
+ });
113
+ dirs.push(acc);
114
+ expect(validateAgentDestination(acc, SUB_A, "whatsapp", "+447958391734")).toEqual({ valid: true });
115
+ });
116
+ it("a number that is both a house admin and a sub-account's manager binds to the sub-account (manager wins)", () => {
117
+ const acc = makeAccountsDir((a) => {
118
+ seedAccount(a, HOUSE, {
119
+ role: "house",
120
+ whatsapp: { adminPhones: ["+447958391734"], accountManagers: { "447958391734": SUB_A } },
121
+ });
122
+ seedAccount(a, SUB_A, {});
123
+ });
124
+ dirs.push(acc);
125
+ // created in SUB_A → its own manager → valid
126
+ expect(validateAgentDestination(acc, SUB_A, "whatsapp", "+447958391734")).toEqual({ valid: true });
58
127
  });
59
128
  });
60
- describe("isValidAgentDestination — telegram", () => {
129
+ describe("validateAgentDestination — telegram unchanged (creating-account dir, house-only)", () => {
61
130
  let dirs = [];
62
131
  afterEach(() => {
63
132
  for (const d of dirs)
64
133
  rmSync(d, { recursive: true, force: true });
65
134
  dirs = [];
66
135
  });
67
- it("accepts a chat id in telegram.adminUsers", () => {
68
- const dir = makeAccountDir({ telegram: { adminUsers: [12345678] } });
69
- dirs.push(dir);
70
- expect(isValidAgentDestination(dir, "telegram", "12345678")).toEqual({ valid: true });
136
+ it("accepts a chat id in the creating account's telegram.adminUsers", () => {
137
+ const acc = makeAccountsDir((a) => seedAccount(a, HOUSE, { role: "house", telegram: { adminUsers: [12345678] } }));
138
+ dirs.push(acc);
139
+ expect(validateAgentDestination(acc, HOUSE, "telegram", "12345678")).toEqual({ valid: true });
71
140
  });
72
- it("rejects a chat id not in adminUsers", () => {
73
- const dir = makeAccountDir({ telegram: { adminUsers: [12345678] } });
74
- dirs.push(dir);
75
- expect(isValidAgentDestination(dir, "telegram", "99999999")).toEqual({
141
+ it("rejects a chat id absent from adminUsers as not-registered", () => {
142
+ const acc = makeAccountsDir((a) => seedAccount(a, HOUSE, { role: "house", telegram: { adminUsers: [12345678] } }));
143
+ dirs.push(acc);
144
+ expect(validateAgentDestination(acc, HOUSE, "telegram", "99999999")).toEqual({
76
145
  valid: false,
77
- reason: "destination-not-admin",
146
+ reason: "not-registered",
78
147
  });
79
148
  });
80
149
  });
81
- describe("boundSubAccountFor — whatsapp accountManagers only", () => {
150
+ describe("boundSubAccountFor — whatsapp accountManagers only (direct single-dir read)", () => {
82
151
  let dirs = [];
83
152
  afterEach(() => {
84
153
  for (const d of dirs)
@@ -1 +1 @@
1
- {"version":3,"file":"agent-dispatch.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/agent-dispatch.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-dispatch.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/agent-dispatch.test.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,23 @@
1
1
  export type AgentChannel = "whatsapp" | "telegram";
2
+ /**
3
+ * Reason codes are the true cause, not a symptom (Task 1439 observability):
4
+ * - `not-registered`: the destination is in no authoritative list (house's
5
+ * `adminPhones`/`accountManagers` for WhatsApp; the creating account's
6
+ * `telegram.adminUsers` for Telegram).
7
+ * - `cross-account`: the destination IS registered, but to an account other
8
+ * than the one that created the schedule (and the creator is not the house).
9
+ * Names both accounts so the mismatch is explained, not guessed.
10
+ */
2
11
  export type DestinationValidity = {
3
12
  valid: true;
4
13
  } | {
5
14
  valid: false;
6
- reason: "destination-not-admin";
15
+ reason: "not-registered";
16
+ } | {
17
+ valid: false;
18
+ reason: "cross-account";
19
+ destinationAccount: string;
20
+ scheduleAccount: string;
7
21
  };
8
22
  /**
9
23
  * Replica of `normalize.ts:normalizeE164` — strip whitespace/dashes/parens, a
@@ -24,20 +38,40 @@ export declare function readChannelAdmins(accountDir: string, channel: "telegram
24
38
  adminUsers: number[];
25
39
  };
26
40
  /**
27
- * A destination is valid iff it is a registered admin or account-manager on
28
- * that channel:
29
- * - whatsapp: `phonesMatch` against any `adminPhones` entry OR any
30
- * `accountManagers` key.
31
- * - telegram: an integer chat id present in `telegram.adminUsers`.
41
+ * The account a WhatsApp `destination` is registered to on the HOUSE's lists,
42
+ * or null if it is in neither list. A manager binding wins over an admin match:
43
+ * if the number is an `accountManagers` key its registered account is the bound
44
+ * sub-account (the isolation-relevant fact); otherwise if it is an `adminPhones`
45
+ * entry its registered account is the house. `houseDir` is the house account's
46
+ * directory; `houseAccountId` its id.
47
+ */
48
+ export declare function registeredAccountForDestination(houseDir: string, houseAccountId: string, destination: string): string | null;
49
+ /**
50
+ * Validate a dispatch destination under the Task 1439 two-part rule.
51
+ * `accountsDir` is the PARENT accounts directory
52
+ * (`$PLATFORM_ROOT/../data/accounts`); `creatingAccountId` is the account that
53
+ * created (or owns) the schedule.
54
+ *
55
+ * - whatsapp: resolve the socket-owning house, read ITS authoritative lists,
56
+ * and compute the destination's registered account. `not-registered` if it
57
+ * is in no house list. Otherwise valid iff the creator IS the house (owner
58
+ * exception: it owns the single line and may target any registered
59
+ * admin/manager) OR the registered account equals the creating account.
60
+ * Any other case is `cross-account`.
61
+ * - telegram: house-only (Task 1378; 1380 deferred). Reads the creating
62
+ * account's own `telegram.adminUsers`; there is no manager surface and thus
63
+ * no cross-account concept — an integer chat id present in the list is valid,
64
+ * anything else is `not-registered`.
32
65
  */
33
- export declare function isValidAgentDestination(accountDir: string, channel: AgentChannel, destination: string): DestinationValidity;
66
+ export declare function validateAgentDestination(accountsDir: string, creatingAccountId: string, channel: AgentChannel, destination: string): DestinationValidity;
34
67
  /**
35
68
  * Validate an `agentDispatch` at write time (shared by `schedule-event` and
36
69
  * `schedule-update` so the two write paths cannot drift on the rule): reject an
37
- * empty prompt, and reject a destination that is not a registered admin or
38
- * account-manager on the channel. Throws with a caller-facing message; returns
39
- * on success. `accountId` is the event's account; its `account.json` under
40
- * `$PLATFORM_ROOT/../data/accounts/<accountId>` holds the channel admin config.
70
+ * empty prompt, and reject a destination that fails the two-part house-authority
71
+ * rule. Throws with a caller-facing message naming the true reason; returns on
72
+ * success. `accountId` is the account that created the schedule — the authority
73
+ * lists are read from the house under `$PLATFORM_ROOT/../data/accounts`, and the
74
+ * destination's registered account must match `accountId` (house/owner aside).
41
75
  */
42
76
  export declare function validateAgentDispatch(accountId: string, agentDispatch: {
43
77
  channel: AgentChannel;
@@ -1 +1 @@
1
- {"version":3,"file":"agent-dispatch.d.ts","sourceRoot":"","sources":["../../src/lib/agent-dispatch.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,UAAU,CAAC;AAEnD,MAAM,MAAM,mBAAmB,GAC3B;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GACf;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,uBAAuB,CAAA;CAAE,CAAC;AAEtD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOnD;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAIzD;AAED,UAAU,cAAc;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED;;uCAEuC;AACvC,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,UAAU,GAClB,cAAc,CAAC;AAClB,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,UAAU,GAClB;IAAE,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AA8B5B;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,MAAM,GAClB,mBAAmB,CAWrB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5E,IAAI,CAgBN;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMzF"}
1
+ {"version":3,"file":"agent-dispatch.d.ts","sourceRoot":"","sources":["../../src/lib/agent-dispatch.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,UAAU,CAAC;AAEnD;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAC3B;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GACf;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAA;CAAE,GAC1C;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,eAAe,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnG;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOnD;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAIzD;AAED,UAAU,cAAc;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED;;uCAEuC;AACvC,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,UAAU,GAClB,cAAc,CAAC;AAClB,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,UAAU,GAClB;IAAE,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AA8B5B;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,IAAI,CAOf;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,iBAAiB,EAAE,MAAM,EACzB,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,MAAM,GAClB,mBAAmB,CAmBrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5E,IAAI,CAsBN;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMzF"}
@@ -1,16 +1,23 @@
1
1
  /**
2
2
  * Task 1378 — agent-bearing scheduled dispatch: destination validation.
3
+ * Task 1439 — house single-authority + creating-account match.
3
4
  *
4
5
  * The scheduling MCP cannot import `platform/ui` (plugin boundary), so this
5
6
  * module replicates the minimal E.164 matching from
6
- * `platform/ui/app/lib/whatsapp/normalize.ts` and reads the channel admin
7
- * config straight out of the account's `account.json`. One implementation is
7
+ * `platform/ui/app/lib/whatsapp/normalize.ts`. For WhatsApp the authoritative
8
+ * `adminPhones` + `accountManagers` lists live ONLY on the socket-owning house
9
+ * account (Tasks 1377/1382), so the validator resolves the house via
10
+ * `resolveHouseOrSoleAccountId` — the same authority the inbound gate uses — and
11
+ * reads its config, NOT the event's own account. It then requires the
12
+ * destination's registered account to match the account that created the
13
+ * schedule (the house/owner account excepted), so a schedule created in account
14
+ * X cannot message another account's people. One `validateAgentDestination` is
8
15
  * shared by `schedule-event`, `schedule-update`, and the dispatcher's standing
9
- * audit so the "is this destination a valid admin/manager" decision cannot
10
- * drift between the write path and the audit.
16
+ * audit so create-time and fire-time cannot diverge on rule or reason codes.
11
17
  */
12
18
  import { readFileSync } from "node:fs";
13
19
  import { resolve } from "node:path";
20
+ import { resolveHouseOrSoleAccountId } from "../../../../../lib/account-enumeration/dist/index.js";
14
21
  /**
15
22
  * Replica of `normalize.ts:normalizeE164` — strip whitespace/dashes/parens, a
16
23
  * `whatsapp:` prefix, and a leading `+` or `00`; return digits-only or `''`.
@@ -60,31 +67,71 @@ export function readChannelAdmins(accountDir, channel) {
60
67
  return { adminUsers };
61
68
  }
62
69
  /**
63
- * A destination is valid iff it is a registered admin or account-manager on
64
- * that channel:
65
- * - whatsapp: `phonesMatch` against any `adminPhones` entry OR any
66
- * `accountManagers` key.
67
- * - telegram: an integer chat id present in `telegram.adminUsers`.
70
+ * The account a WhatsApp `destination` is registered to on the HOUSE's lists,
71
+ * or null if it is in neither list. A manager binding wins over an admin match:
72
+ * if the number is an `accountManagers` key its registered account is the bound
73
+ * sub-account (the isolation-relevant fact); otherwise if it is an `adminPhones`
74
+ * entry its registered account is the house. `houseDir` is the house account's
75
+ * directory; `houseAccountId` its id.
68
76
  */
69
- export function isValidAgentDestination(accountDir, channel, destination) {
77
+ export function registeredAccountForDestination(houseDir, houseAccountId, destination) {
78
+ const { adminPhones, accountManagers } = readChannelAdmins(houseDir, "whatsapp");
79
+ for (const [managerPhone, subAccountId] of Object.entries(accountManagers)) {
80
+ if (subAccountId && phonesMatch(managerPhone, destination))
81
+ return subAccountId;
82
+ }
83
+ if (adminPhones.some((p) => phonesMatch(p, destination)))
84
+ return houseAccountId;
85
+ return null;
86
+ }
87
+ /**
88
+ * Validate a dispatch destination under the Task 1439 two-part rule.
89
+ * `accountsDir` is the PARENT accounts directory
90
+ * (`$PLATFORM_ROOT/../data/accounts`); `creatingAccountId` is the account that
91
+ * created (or owns) the schedule.
92
+ *
93
+ * - whatsapp: resolve the socket-owning house, read ITS authoritative lists,
94
+ * and compute the destination's registered account. `not-registered` if it
95
+ * is in no house list. Otherwise valid iff the creator IS the house (owner
96
+ * exception: it owns the single line and may target any registered
97
+ * admin/manager) OR the registered account equals the creating account.
98
+ * Any other case is `cross-account`.
99
+ * - telegram: house-only (Task 1378; 1380 deferred). Reads the creating
100
+ * account's own `telegram.adminUsers`; there is no manager surface and thus
101
+ * no cross-account concept — an integer chat id present in the list is valid,
102
+ * anything else is `not-registered`.
103
+ */
104
+ export function validateAgentDestination(accountsDir, creatingAccountId, channel, destination) {
70
105
  if (channel === "whatsapp") {
71
- const { adminPhones, accountManagers } = readChannelAdmins(accountDir, "whatsapp");
72
- const inAdmins = adminPhones.some((p) => phonesMatch(p, destination));
73
- const inManagers = Object.keys(accountManagers).some((k) => phonesMatch(k, destination));
74
- return inAdmins || inManagers ? { valid: true } : { valid: false, reason: "destination-not-admin" };
106
+ const houseAccountId = resolveHouseOrSoleAccountId(accountsDir);
107
+ const houseDir = resolve(accountsDir, houseAccountId);
108
+ const registered = registeredAccountForDestination(houseDir, houseAccountId, destination);
109
+ if (registered === null)
110
+ return { valid: false, reason: "not-registered" };
111
+ if (creatingAccountId === houseAccountId)
112
+ return { valid: true };
113
+ if (registered === creatingAccountId)
114
+ return { valid: true };
115
+ return {
116
+ valid: false,
117
+ reason: "cross-account",
118
+ destinationAccount: registered,
119
+ scheduleAccount: creatingAccountId,
120
+ };
75
121
  }
76
- const { adminUsers } = readChannelAdmins(accountDir, "telegram");
122
+ const { adminUsers } = readChannelAdmins(resolve(accountsDir, creatingAccountId), "telegram");
77
123
  const asNumber = Number(destination);
78
124
  const ok = Number.isInteger(asNumber) && adminUsers.includes(asNumber);
79
- return ok ? { valid: true } : { valid: false, reason: "destination-not-admin" };
125
+ return ok ? { valid: true } : { valid: false, reason: "not-registered" };
80
126
  }
81
127
  /**
82
128
  * Validate an `agentDispatch` at write time (shared by `schedule-event` and
83
129
  * `schedule-update` so the two write paths cannot drift on the rule): reject an
84
- * empty prompt, and reject a destination that is not a registered admin or
85
- * account-manager on the channel. Throws with a caller-facing message; returns
86
- * on success. `accountId` is the event's account; its `account.json` under
87
- * `$PLATFORM_ROOT/../data/accounts/<accountId>` holds the channel admin config.
130
+ * empty prompt, and reject a destination that fails the two-part house-authority
131
+ * rule. Throws with a caller-facing message naming the true reason; returns on
132
+ * success. `accountId` is the account that created the schedule — the authority
133
+ * lists are read from the house under `$PLATFORM_ROOT/../data/accounts`, and the
134
+ * destination's registered account must match `accountId` (house/owner aside).
88
135
  */
89
136
  export function validateAgentDispatch(accountId, agentDispatch) {
90
137
  const { channel, destination, prompt } = agentDispatch;
@@ -95,10 +142,14 @@ export function validateAgentDispatch(accountId, agentDispatch) {
95
142
  if (!platformRoot) {
96
143
  throw new Error("PLATFORM_ROOT environment variable is required to validate the agentDispatch destination");
97
144
  }
98
- const accountDir = resolve(platformRoot, "..", "data/accounts", accountId);
99
- const check = isValidAgentDestination(accountDir, channel, destination);
145
+ const accountsDir = resolve(platformRoot, "..", "data/accounts");
146
+ const check = validateAgentDestination(accountsDir, accountId, channel, destination);
100
147
  if (!check.valid) {
101
- throw new Error(`agentDispatch destination "${destination}" is not a registered admin/account-manager on ${channel} — reason=${check.reason}`);
148
+ if (check.reason === "cross-account") {
149
+ throw new Error(`agentDispatch destination "${destination}" belongs to a different account on ${channel} — ` +
150
+ `reason=cross-account destinationAccount=${check.destinationAccount} scheduleAccount=${check.scheduleAccount}`);
151
+ }
152
+ throw new Error(`agentDispatch destination "${destination}" is not a registered admin/account-manager on ${channel} — reason=not-registered`);
102
153
  }
103
154
  }
104
155
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"agent-dispatch.js","sourceRoot":"","sources":["../../src/lib/agent-dispatch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-dispatch.js","sourceRoot":"","sources":["../../src/lib/agent-dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,2BAA2B,EAAE,MAAM,sDAAsD,CAAC;AAkBnG;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,IAAI,SAAS,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACvD,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IACjD,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SACzD,IAAI,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,EAAE,CAAC;IACxC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,WAAW,CAAC,CAAS,EAAE,CAAS;IAC9C,MAAM,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;IAC5B,MAAM,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;IAC5B,OAAO,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;AACpC,CAAC;AAkBD,MAAM,UAAU,iBAAiB,CAC/B,UAAkB,EAClB,OAAqB;IAErB,IAAI,MAAM,GAA4B,EAAE,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAClF,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,EAAE,CAAC;IACd,CAAC;IACD,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAI,MAAM,CAAC,QAAgD,IAAI,EAAE,CAAC;QAC1E,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,CAAC;YAC/C,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;YAClE,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,WAAW,GAAI,EAAE,CAAC,eAAuD,IAAI,EAAE,CAAC;QACtF,MAAM,eAAe,GAA2B,EAAE,CAAC;QACnD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YACjD,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC;IAC1C,CAAC;IACD,MAAM,EAAE,GAAI,MAAM,CAAC,QAAgD,IAAI,EAAE,CAAC;IAC1E,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC;QAC7C,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;QACjE,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,EAAE,UAAU,EAAE,CAAC;AACxB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,+BAA+B,CAC7C,QAAgB,EAChB,cAAsB,EACtB,WAAmB;IAEnB,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,iBAAiB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACjF,KAAK,MAAM,CAAC,YAAY,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;QAC3E,IAAI,YAAY,IAAI,WAAW,CAAC,YAAY,EAAE,WAAW,CAAC;YAAE,OAAO,YAAY,CAAC;IAClF,CAAC;IACD,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;QAAE,OAAO,cAAc,CAAC;IAChF,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,wBAAwB,CACtC,WAAmB,EACnB,iBAAyB,EACzB,OAAqB,EACrB,WAAmB;IAEnB,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QAC3B,MAAM,cAAc,GAAG,2BAA2B,CAAC,WAAW,CAAC,CAAC;QAChE,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;QACtD,MAAM,UAAU,GAAG,+BAA+B,CAAC,QAAQ,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC;QAC1F,IAAI,UAAU,KAAK,IAAI;YAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;QAC3E,IAAI,iBAAiB,KAAK,cAAc;YAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACjE,IAAI,UAAU,KAAK,iBAAiB;YAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAC7D,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,eAAe;YACvB,kBAAkB,EAAE,UAAU;YAC9B,eAAe,EAAE,iBAAiB;SACnC,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,UAAU,EAAE,GAAG,iBAAiB,CAAC,OAAO,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE,UAAU,CAAC,CAAC;IAC9F,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACvE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;AAC3E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CACnC,SAAiB,EACjB,aAA6E;IAE7E,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,aAAa,CAAC;IACvD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAC/C,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,0FAA0F,CAAC,CAAC;IAC9G,CAAC;IACD,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC;IACjE,MAAM,KAAK,GAAG,wBAAwB,CAAC,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IACrF,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACjB,IAAI,KAAK,CAAC,MAAM,KAAK,eAAe,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CACb,8BAA8B,WAAW,uCAAuC,OAAO,KAAK;gBAC1F,2CAA2C,KAAK,CAAC,kBAAkB,oBAAoB,KAAK,CAAC,eAAe,EAAE,CACjH,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,KAAK,CACb,8BAA8B,WAAW,kDAAkD,OAAO,0BAA0B,CAC7H,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAAkB,EAAE,WAAmB;IACxE,MAAM,EAAE,eAAe,EAAE,GAAG,iBAAiB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACtE,KAAK,MAAM,CAAC,YAAY,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;QAC3E,IAAI,YAAY,IAAI,WAAW,CAAC,YAAY,EAAE,WAAW,CAAC;YAAE,OAAO,YAAY,CAAC;IAClF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -13,12 +13,16 @@ function driverReturning(rows) {
13
13
  }),
14
14
  };
15
15
  }
16
+ // The audit now reads the authoritative lists from the socket-owning house, so
17
+ // the house dir must be UUID-named and carry role:"house" (resolver contract).
16
18
  let accountsDir;
17
- const HOUSE = "acct-house";
19
+ const HOUSE = "11111111-1111-4111-8111-111111111111";
20
+ const SUB_OK = "44444444-4444-4444-8444-444444444444";
21
+ const SUB_OTHER = "55555555-5555-4555-8555-555555555555";
18
22
  function seedHouse(waConfig) {
19
23
  const dir = join(accountsDir, HOUSE);
20
24
  mkdirSync(dir, { recursive: true });
21
- writeFileSync(join(dir, "account.json"), JSON.stringify({ whatsapp: waConfig }), "utf-8");
25
+ writeFileSync(join(dir, "account.json"), JSON.stringify({ role: "house", whatsapp: waConfig }), "utf-8");
22
26
  }
23
27
  let errSpy;
24
28
  function auditLines() {
@@ -36,18 +40,31 @@ afterEach(() => {
36
40
  vi.clearAllMocks();
37
41
  });
38
42
  describe("runStandingAudit", () => {
39
- it("emits destination-not-admin when the destination left adminPhones", async () => {
43
+ it("emits not-registered when the destination is in no house list", async () => {
40
44
  seedHouse({ adminPhones: ["+447111111111"] }); // destination not present
41
45
  const driver = driverReturning([
42
46
  { eventId: "e1", accountId: HOUSE, agentChannel: "whatsapp", agentDestination: "+447504472444" },
43
47
  ]);
44
48
  await runStandingAudit(driver, [HOUSE], accountsDir);
45
49
  expect(auditLines()).toEqual([
46
- expect.stringContaining("op=stale-dispatch eventId=e1 reason=destination-not-admin"),
50
+ expect.stringContaining("op=stale-dispatch eventId=e1 reason=not-registered"),
51
+ ]);
52
+ });
53
+ it("emits cross-account when a house event targets a manager bound to a different sub-account", async () => {
54
+ // The manager is bound to SUB_OK, but the event was created in SUB_OTHER.
55
+ seedHouse({ accountManagers: { "447504472444": SUB_OK } });
56
+ mkdirSync(join(accountsDir, SUB_OK), { recursive: true });
57
+ mkdirSync(join(accountsDir, SUB_OTHER), { recursive: true });
58
+ const driver = driverReturning([
59
+ { eventId: "e5", accountId: SUB_OTHER, agentChannel: "whatsapp", agentDestination: "+447504472444" },
60
+ ]);
61
+ await runStandingAudit(driver, [SUB_OTHER], accountsDir);
62
+ expect(auditLines()).toEqual([
63
+ expect.stringContaining(`op=stale-dispatch eventId=e5 reason=cross-account destinationAccount=${SUB_OK} scheduleAccount=${SUB_OTHER}`),
47
64
  ]);
48
65
  });
49
66
  it("emits sub-account-missing when a manager binding points at a deleted sub-account", async () => {
50
- seedHouse({ accountManagers: { "447504472444": "sub-gone" } }); // sub dir never created
67
+ seedHouse({ accountManagers: { "447504472444": "66666666-6666-4666-8666-666666666666" } }); // sub dir never created
51
68
  const driver = driverReturning([
52
69
  { eventId: "e2", accountId: HOUSE, agentChannel: "whatsapp", agentDestination: "+447504472444" },
53
70
  ]);
@@ -56,16 +73,16 @@ describe("runStandingAudit", () => {
56
73
  expect.stringContaining("op=stale-dispatch eventId=e2 reason=sub-account-missing"),
57
74
  ]);
58
75
  });
59
- it("emits nothing for a healthy binding (manager + present sub-account)", async () => {
60
- seedHouse({ accountManagers: { "447504472444": "sub-ok" } });
61
- mkdirSync(join(accountsDir, "sub-ok"), { recursive: true });
76
+ it("emits nothing for a healthy binding (house event, manager + present sub-account)", async () => {
77
+ seedHouse({ accountManagers: { "447504472444": SUB_OK } });
78
+ mkdirSync(join(accountsDir, SUB_OK), { recursive: true });
62
79
  const driver = driverReturning([
63
80
  { eventId: "e3", accountId: HOUSE, agentChannel: "whatsapp", agentDestination: "+447504472444" },
64
81
  ]);
65
82
  await runStandingAudit(driver, [HOUSE], accountsDir);
66
83
  expect(auditLines()).toEqual([]);
67
84
  });
68
- it("emits nothing for a healthy plain admin destination", async () => {
85
+ it("emits nothing for a healthy plain admin destination (house event)", async () => {
69
86
  seedHouse({ adminPhones: ["+447504472444"] });
70
87
  const driver = driverReturning([
71
88
  { eventId: "e4", accountId: HOUSE, agentChannel: "whatsapp", agentDestination: "+447504472444" },
@@ -73,5 +90,27 @@ describe("runStandingAudit", () => {
73
90
  await runStandingAudit(driver, [HOUSE], accountsDir);
74
91
  expect(auditLines()).toEqual([]);
75
92
  });
93
+ it("emits nothing when a sub-account event targets its OWN manager", async () => {
94
+ seedHouse({ accountManagers: { "447504472444": SUB_OK } });
95
+ mkdirSync(join(accountsDir, SUB_OK), { recursive: true });
96
+ const driver = driverReturning([
97
+ { eventId: "e6", accountId: SUB_OK, agentChannel: "whatsapp", agentDestination: "+447504472444" },
98
+ ]);
99
+ await runStandingAudit(driver, [SUB_OK], accountsDir);
100
+ expect(auditLines()).toEqual([]);
101
+ });
102
+ it("never throws on house drift (multi-house): returns with op=house-unresolved", async () => {
103
+ // Two role:"house" dirs — the resolver loud-fails. The audit must not throw
104
+ // into the sweep; it emits one diagnostic and returns.
105
+ seedHouse({ adminPhones: ["+447504472444"] });
106
+ const secondHouse = "77777777-7777-4777-8777-777777777777";
107
+ mkdirSync(join(accountsDir, secondHouse), { recursive: true });
108
+ writeFileSync(join(accountsDir, secondHouse, "account.json"), JSON.stringify({ role: "house", whatsapp: {} }), "utf-8");
109
+ const driver = driverReturning([
110
+ { eventId: "e7", accountId: HOUSE, agentChannel: "whatsapp", agentDestination: "+447504472444" },
111
+ ]);
112
+ await expect(runStandingAudit(driver, [HOUSE], accountsDir)).resolves.toBeUndefined();
113
+ expect(auditLines().some((l) => l.includes("op=house-unresolved"))).toBe(true);
114
+ });
76
115
  });
77
116
  //# sourceMappingURL=standing-audit.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"standing-audit.test.js","sourceRoot":"","sources":["../../../src/scripts/__tests__/standing-audit.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"standing-audit.test.js","sourceRoot":"","sources":["../../../src/scripts/__tests__/standing-audit.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAS7D,SAAS,eAAe,CAAC,IAAgB;IACvC,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;YACd,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBACtB,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAiB,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;aACjE,CAAC,CAAC;YACH,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,GAAE,CAAC,CAAC;SAC7B,CAAC;KACH,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,+EAA+E;AAC/E,IAAI,WAAmB,CAAC;AACxB,MAAM,KAAK,GAAG,sCAAsC,CAAC;AACrD,MAAM,MAAM,GAAG,sCAAsC,CAAC;AACtD,MAAM,SAAS,GAAG,sCAAsC,CAAC;AAEzD,SAAS,SAAS,CAAC,QAAiC;IAClD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IACrC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AAC3G,CAAC;AAED,IAAI,MAAmC,CAAC;AACxC,SAAS,UAAU;IACjB,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK;SACrB,GAAG,CAAC,CAAC,CAAY,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACnC,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,UAAU,CAAC,GAAG,EAAE;IACd,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC7D,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AACnE,CAAC,CAAC,CAAC;AACH,SAAS,CAAC,GAAG,EAAE;IACb,MAAM,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,MAAM,CAAC,WAAW,EAAE,CAAC;IACrB,EAAE,CAAC,aAAa,EAAE,CAAC;AACrB,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,0BAA0B;QACzE,MAAM,MAAM,GAAG,eAAe,CAAC;YAC7B,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,EAAE;SACjG,CAAC,CAAC;QACH,MAAM,gBAAgB,CAAC,MAAe,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC,CAAC;QAC9D,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC;YAC3B,MAAM,CAAC,gBAAgB,CAAC,oDAAoD,CAAC;SAC9E,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2FAA2F,EAAE,KAAK,IAAI,EAAE;QACzG,0EAA0E;QAC1E,SAAS,CAAC,EAAE,eAAe,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3D,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,eAAe,CAAC;YAC7B,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,EAAE;SACrG,CAAC,CAAC;QACH,MAAM,gBAAgB,CAAC,MAAe,EAAE,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC,CAAC;QAClE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC;YAC3B,MAAM,CAAC,gBAAgB,CACrB,wEAAwE,MAAM,oBAAoB,SAAS,EAAE,CAC9G;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kFAAkF,EAAE,KAAK,IAAI,EAAE;QAChG,SAAS,CAAC,EAAE,eAAe,EAAE,EAAE,cAAc,EAAE,sCAAsC,EAAE,EAAE,CAAC,CAAC,CAAC,wBAAwB;QACpH,MAAM,MAAM,GAAG,eAAe,CAAC;YAC7B,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,EAAE;SACjG,CAAC,CAAC;QACH,MAAM,gBAAgB,CAAC,MAAe,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC,CAAC;QAC9D,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC;YAC3B,MAAM,CAAC,gBAAgB,CAAC,yDAAyD,CAAC;SACnF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kFAAkF,EAAE,KAAK,IAAI,EAAE;QAChG,SAAS,CAAC,EAAE,eAAe,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3D,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,eAAe,CAAC;YAC7B,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,EAAE;SACjG,CAAC,CAAC;QACH,MAAM,gBAAgB,CAAC,MAAe,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC,CAAC;QAC9D,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,eAAe,CAAC;YAC7B,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,EAAE;SACjG,CAAC,CAAC;QACH,MAAM,gBAAgB,CAAC,MAAe,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC,CAAC;QAC9D,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,SAAS,CAAC,EAAE,eAAe,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3D,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,eAAe,CAAC;YAC7B,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,EAAE;SAClG,CAAC,CAAC;QACH,MAAM,gBAAgB,CAAC,MAAe,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC;QAC/D,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6EAA6E,EAAE,KAAK,IAAI,EAAE;QAC3F,4EAA4E;QAC5E,uDAAuD;QACvD,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QAC9C,MAAM,WAAW,GAAG,sCAAsC,CAAC;QAC3D,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,aAAa,CACX,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,cAAc,CAAC,EAC9C,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,EAC/C,OAAO,CACR,CAAC;QACF,MAAM,MAAM,GAAG,eAAe,CAAC;YAC7B,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,EAAE;SACjG,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,gBAAgB,CAAC,MAAe,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;QAC/F,MAAM,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -48,12 +48,16 @@ export declare function dispatchAgentTurn(eventId: string, channel: string, dest
48
48
  /**
49
49
  * The no-event detector. Each heartbeat tick, over every agent-dispatch event
50
50
  * for a local account, re-checks the destination binding against the current
51
- * channel config so a destination removed from `adminPhones`/`accountManagers`
52
- * out of band — or a manager whose sub-account was deleted — is surfaced before
53
- * the next fire silently mis-dispatches. Independent of any inbound: it reads
54
- * the node and the on-disk config, nothing else. Emits one
51
+ * channel config so a destination removed from the house's
52
+ * `adminPhones`/`accountManagers` out of band — a manager rebound to another
53
+ * sub-account, or a manager whose sub-account was deleted is surfaced before
54
+ * the next fire silently mis-dispatches. It applies the SAME two-part rule
55
+ * (`validateAgentDestination`) create-time validation uses, so a schedule that
56
+ * passed creation but later drifts is explained with the identical reason codes
57
+ * rather than silently dropped (Task 1439). Independent of any inbound: it reads
58
+ * the node and the on-disk house config, nothing else. Emits one
55
59
  * `[schedule-audit] op=stale-dispatch` line per invalid binding; a healthy
56
- * binding emits nothing.
60
+ * binding emits nothing. Never throws (honours the sweep's contract).
57
61
  */
58
62
  export declare function runStandingAudit(driver: Driver, localAccountIds: string[], accountsDir: string): Promise<void>;
59
63
  //# sourceMappingURL=agent-turn-dispatch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-turn-dispatch.d.ts","sourceRoot":"","sources":["../../src/scripts/agent-turn-dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAS3C,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GAAG,YAAY,CAaf;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CA0Df;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,EAAE,EACzB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAuCf"}
1
+ {"version":3,"file":"agent-turn-dispatch.d.ts","sourceRoot":"","sources":["../../src/scripts/agent-turn-dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAU3C,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GAAG,YAAY,CAaf;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CA0Df;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,EAAE,EACzB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CA8Ef"}
@@ -1,6 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { join } from "node:path";
3
- import { isValidAgentDestination, boundSubAccountFor, } from "../lib/agent-dispatch.js";
3
+ import { validateAgentDestination, boundSubAccountFor, } from "../lib/agent-dispatch.js";
4
+ import { resolveHouseOrSoleAccountId } from "../../../../../lib/account-enumeration/dist/index.js";
4
5
  /**
5
6
  * Decide how a due event dispatches from its selected node fields. An event
6
7
  * carries at most one mode (enforced at write); agent dispatch takes precedence
@@ -83,12 +84,16 @@ export async function dispatchAgentTurn(eventId, channel, destination, prompt, e
83
84
  /**
84
85
  * The no-event detector. Each heartbeat tick, over every agent-dispatch event
85
86
  * for a local account, re-checks the destination binding against the current
86
- * channel config so a destination removed from `adminPhones`/`accountManagers`
87
- * out of band — or a manager whose sub-account was deleted — is surfaced before
88
- * the next fire silently mis-dispatches. Independent of any inbound: it reads
89
- * the node and the on-disk config, nothing else. Emits one
87
+ * channel config so a destination removed from the house's
88
+ * `adminPhones`/`accountManagers` out of band — a manager rebound to another
89
+ * sub-account, or a manager whose sub-account was deleted is surfaced before
90
+ * the next fire silently mis-dispatches. It applies the SAME two-part rule
91
+ * (`validateAgentDestination`) create-time validation uses, so a schedule that
92
+ * passed creation but later drifts is explained with the identical reason codes
93
+ * rather than silently dropped (Task 1439). Independent of any inbound: it reads
94
+ * the node and the on-disk house config, nothing else. Emits one
90
95
  * `[schedule-audit] op=stale-dispatch` line per invalid binding; a healthy
91
- * binding emits nothing.
96
+ * binding emits nothing. Never throws (honours the sweep's contract).
92
97
  */
93
98
  export async function runStandingAudit(driver, localAccountIds, accountsDir) {
94
99
  if (localAccountIds.length === 0)
@@ -111,20 +116,50 @@ export async function runStandingAudit(driver, localAccountIds, accountsDir) {
111
116
  finally {
112
117
  await session.close();
113
118
  }
119
+ // The authoritative WhatsApp lists live on the socket-owning house; resolve it
120
+ // once up front for the sub-account-missing check. `validateAgentDestination`
121
+ // re-resolves the house per row, so a house that is unresolvable for the whole
122
+ // tick (zero/multi house — genuine drift) is caught here and the audit returns
123
+ // with one diagnostic. The per-row body is ALSO guarded below, so a house that
124
+ // becomes unresolvable mid-tick (a re-roll between this resolve and a later row)
125
+ // degrades that row to `op=house-unresolved` and continues — the audit never
126
+ // throws either way.
127
+ let houseDir;
128
+ try {
129
+ houseDir = join(accountsDir, resolveHouseOrSoleAccountId(accountsDir));
130
+ }
131
+ catch (err) {
132
+ console.error(`[schedule-audit] op=house-unresolved detail=${err instanceof Error ? err.message : String(err)}`);
133
+ return;
134
+ }
114
135
  for (const row of rows) {
115
- const accountDir = join(accountsDir, row.accountId);
116
- const check = isValidAgentDestination(accountDir, row.agentChannel, row.agentDestination);
117
- if (!check.valid) {
118
- console.error(`[schedule-audit] op=stale-dispatch eventId=${row.eventId} reason=destination-not-admin`);
119
- continue;
120
- }
121
- // A still-valid WhatsApp manager destination whose bound sub-account directory
122
- // is gone would spawn against a missing account — surface it distinctly.
123
- if (row.agentChannel === "whatsapp") {
124
- const sub = boundSubAccountFor(accountDir, row.agentDestination);
125
- if (sub && !existsSync(join(accountsDir, sub))) {
126
- console.error(`[schedule-audit] op=stale-dispatch eventId=${row.eventId} reason=sub-account-missing`);
136
+ try {
137
+ const check = validateAgentDestination(accountsDir, row.accountId, row.agentChannel, row.agentDestination);
138
+ if (!check.valid) {
139
+ if (check.reason === "cross-account") {
140
+ console.error(`[schedule-audit] op=stale-dispatch eventId=${row.eventId} reason=cross-account ` +
141
+ `destinationAccount=${check.destinationAccount} scheduleAccount=${check.scheduleAccount}`);
142
+ }
143
+ else {
144
+ console.error(`[schedule-audit] op=stale-dispatch eventId=${row.eventId} reason=not-registered`);
145
+ }
146
+ continue;
127
147
  }
148
+ // A still-valid WhatsApp manager destination whose bound sub-account directory
149
+ // is gone would spawn against a missing account — surface it distinctly. The
150
+ // binding lives on the house, so read it from the house dir.
151
+ if (row.agentChannel === "whatsapp") {
152
+ const sub = boundSubAccountFor(houseDir, row.agentDestination);
153
+ if (sub && !existsSync(join(accountsDir, sub))) {
154
+ console.error(`[schedule-audit] op=stale-dispatch eventId=${row.eventId} reason=sub-account-missing`);
155
+ }
156
+ }
157
+ }
158
+ catch (err) {
159
+ // A mid-tick house re-roll can make the per-row house resolution throw.
160
+ // Honour the never-throws contract: log this row and keep sweeping.
161
+ console.error(`[schedule-audit] op=house-unresolved eventId=${row.eventId} ` +
162
+ `detail=${err instanceof Error ? err.message : String(err)}`);
128
163
  }
129
164
  }
130
165
  }
@@ -1 +1 @@
1
- {"version":3,"file":"agent-turn-dispatch.js","sourceRoot":"","sources":["../../src/scripts/agent-turn-dispatch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-turn-dispatch.js","sourceRoot":"","sources":["../../src/scripts/agent-turn-dispatch.ts"],"names":[],"mappings":"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"}
@@ -23,11 +23,19 @@ vi.mock("../../../../../../lib/graph-write/dist/index.js", () => ({
23
23
  import { scheduleEvent } from "../schedule-event.js";
24
24
  const CREATED_BY = { agent: "admin", session: "sess-1", tool: "schedule-event" };
25
25
  let platformRoot;
26
- const ACCOUNT_ID = "acct-house";
26
+ // The validator resolves the socket-owning house, so the account dir must be
27
+ // UUID-named and carry role:"house" (account-enumeration resolver contract).
28
+ const ACCOUNT_ID = "11111111-1111-4111-8111-111111111111";
29
+ const SUB_A = "22222222-2222-4222-8222-222222222222";
27
30
  function seedAccount(waConfig) {
28
31
  const accountDir = join(platformRoot, "..", "data", "accounts", ACCOUNT_ID);
29
32
  mkdirSync(accountDir, { recursive: true });
30
- writeFileSync(join(accountDir, "account.json"), JSON.stringify({ whatsapp: waConfig }), "utf-8");
33
+ writeFileSync(join(accountDir, "account.json"), JSON.stringify({ role: "house", whatsapp: waConfig }), "utf-8");
34
+ }
35
+ function seedSub(id, cfg) {
36
+ const d = join(platformRoot, "..", "data", "accounts", id);
37
+ mkdirSync(d, { recursive: true });
38
+ writeFileSync(join(d, "account.json"), JSON.stringify(cfg), "utf-8");
31
39
  }
32
40
  beforeEach(() => {
33
41
  writeCalls.length = 0;
@@ -74,7 +82,7 @@ describe("scheduleEvent — agentDispatch validation", () => {
74
82
  agentDispatch: { channel: "whatsapp", destination: "+447504472444", prompt: " " },
75
83
  })).rejects.toThrow(/prompt/i);
76
84
  });
77
- it("rejects a destination that is not an admin/manager", async () => {
85
+ it("rejects a destination that is in no house list (not-registered)", async () => {
78
86
  seedAccount({ adminPhones: ["+447504472444"] });
79
87
  await expect(scheduleEvent({
80
88
  accountId: ACCOUNT_ID,
@@ -83,7 +91,19 @@ describe("scheduleEvent — agentDispatch validation", () => {
83
91
  sessionKey: "s",
84
92
  createdBy: CREATED_BY,
85
93
  agentDispatch: { channel: "whatsapp", destination: "+447999999999", prompt: "hi" },
86
- })).rejects.toThrow(/destination-not-admin/);
94
+ })).rejects.toThrow(/not-registered/);
95
+ });
96
+ it("rejects cross-account: schedule created in a sub-account targeting a house admin", async () => {
97
+ seedAccount({ adminPhones: ["+447504472444"] }); // house
98
+ seedSub(SUB_A, {}); // creating sub-account, no managers of its own
99
+ await expect(scheduleEvent({
100
+ accountId: SUB_A,
101
+ name: "e",
102
+ startDate: "2026-07-03T09:00:00Z",
103
+ sessionKey: "s",
104
+ createdBy: CREATED_BY,
105
+ agentDispatch: { channel: "whatsapp", destination: "+447504472444", prompt: "hi" },
106
+ })).rejects.toThrow(/cross-account/);
87
107
  });
88
108
  it("persists agentChannel/agentDestination/agentPrompt for a valid destination", async () => {
89
109
  // spaced form must validate against the stored bare adminPhones entry
@@ -1 +1 @@
1
- {"version":3,"file":"schedule-event-agent.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/schedule-event-agent.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schedule-event-agent.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/schedule-event-agent.test.ts"],"names":[],"mappings":"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"}
@@ -18,11 +18,13 @@ vi.mock("../../lib/neo4j.js", () => ({
18
18
  }));
19
19
  import { scheduleUpdate } from "../schedule-update.js";
20
20
  let platformRoot;
21
- const ACCOUNT_ID = "acct-house";
21
+ // UUID-named house dir carrying role:"house" — the validator resolves the house
22
+ // via account-enumeration, which requires this shape.
23
+ const ACCOUNT_ID = "11111111-1111-4111-8111-111111111111";
22
24
  function seedAccount(waConfig) {
23
25
  const accountDir = join(platformRoot, "..", "data", "accounts", ACCOUNT_ID);
24
26
  mkdirSync(accountDir, { recursive: true });
25
- writeFileSync(join(accountDir, "account.json"), JSON.stringify({ whatsapp: waConfig }), "utf-8");
27
+ writeFileSync(join(accountDir, "account.json"), JSON.stringify({ role: "house", whatsapp: waConfig }), "utf-8");
26
28
  }
27
29
  function lastSet() {
28
30
  return runCalls[runCalls.length - 1];
@@ -69,13 +71,13 @@ describe("scheduleUpdate — agentDispatch", () => {
69
71
  agentDispatch: { channel: "whatsapp", destination: "+447504472444", prompt: "hi" },
70
72
  })).rejects.toThrow(/both/i);
71
73
  });
72
- it("rejects a destination that is not an admin/manager", async () => {
74
+ it("rejects a destination that is in no house list (not-registered)", async () => {
73
75
  seedAccount({ adminPhones: ["+447504472444"] });
74
76
  await expect(scheduleUpdate({
75
77
  accountId: ACCOUNT_ID,
76
78
  eventId: "e1",
77
79
  agentDispatch: { channel: "whatsapp", destination: "+447999999999", prompt: "hi" },
78
- })).rejects.toThrow(/destination-not-admin/);
80
+ })).rejects.toThrow(/not-registered/);
79
81
  });
80
82
  });
81
83
  //# sourceMappingURL=schedule-update-agent.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schedule-update-agent.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/schedule-update-agent.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schedule-update-agent.test.js","sourceRoot":"","sources":["../../../src/tools/__tests__/schedule-update-agent.test.ts"],"names":[],"mappings":"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"}
@@ -115,6 +115,8 @@ The platform enforces this at multiple levels:
115
115
 
116
116
  **The scheduler path fails closed too.** A scheduled dispatch (`POST /api/channel/schedule-inject`) reaches the same spawn machine without going through the gate, resolving its own effective account via `effectiveAccountFor`. That resolver carries the same single-source + fail-closed shape: a non-manager destination scopes to the house (an owner/admin's real scope), a valid manager scopes to the bound sub-account, and a manager whose bound sub-account is not a valid account resolves to nothing — the route **rejects** (`op=schedule-account-manager-reject … reason=unresolved-effective-account`, HTTP 403, no spawn, no reply), never routing to the house. There is no `?? accountId` fallback on this path either. Telegram scheduled dispatch is house-only by construction (no account-manager routing), so there is nothing to fail closed there.
117
117
 
118
+ **Schedule-time destination validation is a distinct, earlier layer.** The `effectiveAccountFor` resolution above runs at *fire* time to scope the spawn. Separately, when a schedule is *created or updated* (and re-checked every heartbeat by the standing audit), the scheduler validates the WhatsApp `agentDispatch` destination against the same house authority. It reads the authoritative `adminPhones` + `accountManagers` from the socket-owning **house** account — never the event's own `account.json`, whose manager map is inert — via the one shared `validateAgentDestination`. The destination's registered account (the house for an admin, the bound sub-account for a manager) must equal the account that created the schedule; the house/owner may target any registered admin or manager, a sub-account is locked to its own manager(s). A refusal names the true cause: `not-registered` (in no house list) or `cross-account destinationAccount=… scheduleAccount=…` (registered to a different account). Create-time and fire-time emit the identical reason codes, so a schedule that passes creation but later drifts is explained rather than silently dropped. This closes the bug where the validator read a sub-account's own (empty) manager map and refused a genuinely registered manager whose binding lives on the house.
119
+
118
120
  **Socket-key resolution — the reply transport.** The account id that names a *spawn scope* (a platform account UUID) is a different identifier from the key the *socket* is stored under (the credential dirname — `"default"` on a legacy single-account install that was never re-keyed to the UUID). These coincide when the credential dir is named for the UUID and diverge otherwise. The inbound reply path never trips on this: it closes over the live connection object directly. A scheduled dispatch has no live connection to close over, so it resolves the socket by asking the manager — `resolveSocket(accountId)` accepts **either** the platform UUID or the connection map key and returns the one connection that owns the socket (the manager holds the `accountId ↔ platformAccountId` bijection). This is the single resolver both the reply path and the scheduler go through, so the id `getSocket` is called with is always a key the connection map actually holds. A null resolution is **two distinct faults, never conflated**: `op=socket-key-miss accountId=… presentKeys=…` means no connection is registered under that id — an account-keying mismatch, the socket may be alive under a different key, and re-pairing is the wrong advice; a *disconnected* result means the connection exists but its transport is down. Reporting a key miss as "WhatsApp disconnected" is the bug that once told an operator to re-sign-in a connected line.
119
121
 
120
122
  **`dmPolicy` behaviour (per-account):**
@@ -10520,6 +10520,7 @@ import { dirname as dirname8, join as join23 } from "path";
10520
10520
 
10521
10521
  // app/lib/claude-keychain.ts
10522
10522
  import { execFileSync as execFileSync2 } from "child_process";
10523
+ import { userInfo } from "os";
10523
10524
  var CREDS_SERVICE_PREFIX = "Claude Code-credentials";
10524
10525
  function parseKeychainMdats(dumpOutput) {
10525
10526
  const out = {};
@@ -10607,18 +10608,35 @@ function decodeKeychainBlob(raw) {
10607
10608
  }
10608
10609
  return raw;
10609
10610
  }
10610
- function readHostCredsBlob(service) {
10611
+ function readOnce(args) {
10611
10612
  try {
10612
- const raw = execFileSync2("security", ["find-generic-password", "-w", "-s", service], {
10613
+ const raw = execFileSync2("security", ["find-generic-password", "-w", ...args], {
10613
10614
  encoding: "utf-8",
10614
10615
  timeout: 1e4
10615
10616
  }).trim();
10616
- if (raw.length === 0) return null;
10617
- return decodeKeychainBlob(raw);
10617
+ return raw.length > 0 ? decodeKeychainBlob(raw) : null;
10618
10618
  } catch {
10619
10619
  return null;
10620
10620
  }
10621
10621
  }
10622
+ function credentialReadAttempts(service, username) {
10623
+ const attempts = [];
10624
+ if (username) attempts.push(["-s", service, "-a", username]);
10625
+ attempts.push(["-s", service]);
10626
+ return attempts;
10627
+ }
10628
+ function readHostCredsBlob(service) {
10629
+ let username = "";
10630
+ try {
10631
+ username = userInfo().username;
10632
+ } catch {
10633
+ }
10634
+ for (const args of credentialReadAttempts(service, username)) {
10635
+ const blob = readOnce(args);
10636
+ if (blob !== null) return blob;
10637
+ }
10638
+ return null;
10639
+ }
10622
10640
 
10623
10641
  // ../lib/admins-write/src/index.ts
10624
10642
  import { existsSync as existsSync14, readFileSync as readFileSync23, writeFileSync as writeFileSync9, renameSync as renameSync6, mkdirSync as mkdirSync5, readdirSync as readdirSync13, statSync as statSync8, appendFileSync as appendFileSync2 } from "fs";