@animalabs/agent-framework 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/dist/src/agent.d.ts +1 -1
  2. package/dist/src/agent.d.ts.map +1 -1
  3. package/dist/src/agent.js.map +1 -1
  4. package/dist/src/framework.d.ts +72 -4
  5. package/dist/src/framework.d.ts.map +1 -1
  6. package/dist/src/framework.js +699 -48
  7. package/dist/src/framework.js.map +1 -1
  8. package/dist/src/gate/event-gate.d.ts +62 -7
  9. package/dist/src/gate/event-gate.d.ts.map +1 -1
  10. package/dist/src/gate/event-gate.js +333 -22
  11. package/dist/src/gate/event-gate.js.map +1 -1
  12. package/dist/src/gate/types.d.ts +56 -0
  13. package/dist/src/gate/types.d.ts.map +1 -1
  14. package/dist/src/mcpl/prose-grammar.d.ts +11 -0
  15. package/dist/src/mcpl/prose-grammar.d.ts.map +1 -1
  16. package/dist/src/mcpl/prose-grammar.js +21 -0
  17. package/dist/src/mcpl/prose-grammar.js.map +1 -1
  18. package/dist/src/mcpl/prose-stream-router.d.ts +2 -2
  19. package/dist/src/mcpl/prose-stream-router.d.ts.map +1 -1
  20. package/dist/src/mcpl/prose-stream-router.js +57 -13
  21. package/dist/src/mcpl/prose-stream-router.js.map +1 -1
  22. package/dist/src/modules/discord/index.d.ts.map +1 -1
  23. package/dist/src/modules/discord/index.js +21 -5
  24. package/dist/src/modules/discord/index.js.map +1 -1
  25. package/dist/src/modules/workspace/index.d.ts +23 -0
  26. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  27. package/dist/src/modules/workspace/index.js +53 -3
  28. package/dist/src/modules/workspace/index.js.map +1 -1
  29. package/dist/src/modules/workspace/sync.d.ts +11 -2
  30. package/dist/src/modules/workspace/sync.d.ts.map +1 -1
  31. package/dist/src/modules/workspace/sync.js +27 -11
  32. package/dist/src/modules/workspace/sync.js.map +1 -1
  33. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  34. package/dist/src/modules/workspace/watcher.js +9 -6
  35. package/dist/src/modules/workspace/watcher.js.map +1 -1
  36. package/dist/src/queue.d.ts.map +1 -1
  37. package/dist/src/queue.js +9 -2
  38. package/dist/src/queue.js.map +1 -1
  39. package/dist/src/tool-result-history.d.ts +12 -2
  40. package/dist/src/tool-result-history.d.ts.map +1 -1
  41. package/dist/src/tool-result-history.js +12 -2
  42. package/dist/src/tool-result-history.js.map +1 -1
  43. package/dist/src/types/agent.d.ts +6 -1
  44. package/dist/src/types/agent.d.ts.map +1 -1
  45. package/dist/src/types/framework.d.ts +1 -1
  46. package/dist/src/types/trace.d.ts +7 -0
  47. package/dist/src/types/trace.d.ts.map +1 -1
  48. package/dist/test/busy-agent-scheduler.test.js +29 -0
  49. package/dist/test/busy-agent-scheduler.test.js.map +1 -1
  50. package/dist/test/discord-history-delete-window.test.d.ts +2 -0
  51. package/dist/test/discord-history-delete-window.test.d.ts.map +1 -0
  52. package/dist/test/discord-history-delete-window.test.js +81 -0
  53. package/dist/test/discord-history-delete-window.test.js.map +1 -0
  54. package/dist/test/discord-history-sync.test.d.ts +2 -0
  55. package/dist/test/discord-history-sync.test.d.ts.map +1 -0
  56. package/dist/test/discord-history-sync.test.js +56 -0
  57. package/dist/test/discord-history-sync.test.js.map +1 -0
  58. package/dist/test/event-gate-passthrough.test.d.ts +15 -0
  59. package/dist/test/event-gate-passthrough.test.d.ts.map +1 -0
  60. package/dist/test/event-gate-passthrough.test.js +289 -0
  61. package/dist/test/event-gate-passthrough.test.js.map +1 -0
  62. package/dist/test/explicit-prose-routing.test.js +179 -7
  63. package/dist/test/explicit-prose-routing.test.js.map +1 -1
  64. package/dist/test/framework.test.js +33 -0
  65. package/dist/test/framework.test.js.map +1 -1
  66. package/dist/test/prose-stream-router.test.js +43 -0
  67. package/dist/test/prose-stream-router.test.js.map +1 -1
  68. package/dist/test/provider-acceleration-cooldown.test.d.ts +2 -0
  69. package/dist/test/provider-acceleration-cooldown.test.d.ts.map +1 -0
  70. package/dist/test/provider-acceleration-cooldown.test.js +286 -0
  71. package/dist/test/provider-acceleration-cooldown.test.js.map +1 -0
  72. package/dist/test/puppet-tool-call.test.d.ts +2 -0
  73. package/dist/test/puppet-tool-call.test.d.ts.map +1 -0
  74. package/dist/test/puppet-tool-call.test.js +106 -0
  75. package/dist/test/puppet-tool-call.test.js.map +1 -0
  76. package/dist/test/release-changelog.test.d.ts +2 -0
  77. package/dist/test/release-changelog.test.d.ts.map +1 -0
  78. package/dist/test/release-changelog.test.js +159 -0
  79. package/dist/test/release-changelog.test.js.map +1 -0
  80. package/dist/test/tool-result-spill.test.d.ts +1 -1
  81. package/dist/test/tool-result-spill.test.js +18 -9
  82. package/dist/test/tool-result-spill.test.js.map +1 -1
  83. package/dist/test/workspace-path-containment.test.d.ts +19 -0
  84. package/dist/test/workspace-path-containment.test.d.ts.map +1 -0
  85. package/dist/test/workspace-path-containment.test.js +91 -0
  86. package/dist/test/workspace-path-containment.test.js.map +1 -0
  87. package/dist/test/workspace-watcher.test.js +15 -3
  88. package/dist/test/workspace-watcher.test.js.map +1 -1
  89. package/dist/test/xml-round-persist.test.d.ts +19 -0
  90. package/dist/test/xml-round-persist.test.d.ts.map +1 -0
  91. package/dist/test/xml-round-persist.test.js +235 -0
  92. package/dist/test/xml-round-persist.test.js.map +1 -0
  93. package/dist/tsconfig.tsbuildinfo +1 -1
  94. package/package.json +2 -1
  95. package/src/agent.ts +1 -1
  96. package/src/framework.ts +733 -48
  97. package/src/gate/event-gate.ts +355 -24
  98. package/src/gate/types.ts +58 -0
  99. package/src/mcpl/prose-grammar.ts +21 -0
  100. package/src/mcpl/prose-stream-router.ts +48 -14
  101. package/src/modules/discord/index.ts +24 -6
  102. package/src/modules/workspace/index.ts +53 -3
  103. package/src/modules/workspace/sync.ts +39 -10
  104. package/src/modules/workspace/watcher.ts +9 -6
  105. package/src/queue.ts +8 -2
  106. package/src/tool-result-history.ts +12 -2
  107. package/src/types/agent.ts +6 -1
  108. package/src/types/framework.ts +1 -1
  109. package/src/types/trace.ts +13 -0
@@ -0,0 +1,81 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { DiscordModule } from '../src/modules/discord/index.js';
4
+ function historyMessage(id, timestamp) {
5
+ return {
6
+ id,
7
+ authorId: `author-${id}`,
8
+ authorName: `Author ${id}`,
9
+ isBot: false,
10
+ content: `message ${id}`,
11
+ timestamp: new Date(timestamp),
12
+ };
13
+ }
14
+ function storedMessage(internalId, externalId, timestamp) {
15
+ return {
16
+ id: internalId,
17
+ sequence: 1,
18
+ participant: `Author ${externalId}`,
19
+ content: [{ type: 'text', text: `message ${externalId}` }],
20
+ metadata: {
21
+ external: { source: 'discord', id: externalId },
22
+ channelId: 'channel-1',
23
+ timestamp,
24
+ },
25
+ timestamp: new Date(timestamp),
26
+ };
27
+ }
28
+ function historyHarness(discordMessages, storedMessages, historyScrollback) {
29
+ const client = {
30
+ fetchHistory: async () => discordMessages,
31
+ };
32
+ const module = new DiscordModule(client, {
33
+ token: 'test-token',
34
+ historyScrollback,
35
+ });
36
+ const harness = module;
37
+ const removed = [];
38
+ harness.ctx = {
39
+ queryMessages: () => ({
40
+ messages: storedMessages,
41
+ totalCount: storedMessages.length,
42
+ }),
43
+ getAgents: () => [{ name: 'Sol' }],
44
+ addMessage: () => 'unexpected-add',
45
+ editMessage: () => { },
46
+ removeMessage: (id) => removed.push(id),
47
+ };
48
+ return { harness, removed };
49
+ }
50
+ test('history sync preserves stored messages older than a full scrollback window', async () => {
51
+ const { harness, removed } = historyHarness([historyMessage('3', 3_000), historyMessage('2', 2_000)], [
52
+ storedMessage('stored-old', '1', 1_000),
53
+ storedMessage('stored-recent-deleted', 'deleted', 2_500),
54
+ storedMessage('stored-2', '2', 2_000),
55
+ storedMessage('stored-3', '3', 3_000),
56
+ ], 2);
57
+ const result = await harness.syncChannelHistory('channel-1');
58
+ assert.deepStrictEqual(removed, ['stored-recent-deleted']);
59
+ assert.equal(result.deletedMessages, 1);
60
+ });
61
+ test('history sync preserves an unfetched message tied with the oldest fetched timestamp', async () => {
62
+ const { harness, removed } = historyHarness([historyMessage('3', 3_000), historyMessage('2', 2_000)], [
63
+ storedMessage('stored-boundary-unseen', '1', 2_000),
64
+ storedMessage('stored-recent-deleted', 'deleted', 2_500),
65
+ storedMessage('stored-2', '2', 2_000),
66
+ storedMessage('stored-3', '3', 3_000),
67
+ ], 2);
68
+ const result = await harness.syncChannelHistory('channel-1');
69
+ assert.deepStrictEqual(removed, ['stored-recent-deleted']);
70
+ assert.equal(result.deletedMessages, 1);
71
+ });
72
+ test('history sync still detects older deletions when the fetch covers the whole channel', async () => {
73
+ const { harness, removed } = historyHarness([historyMessage('2', 2_000)], [
74
+ storedMessage('stored-deleted', '1', 1_000),
75
+ storedMessage('stored-2', '2', 2_000),
76
+ ], 3);
77
+ const result = await harness.syncChannelHistory('channel-1');
78
+ assert.deepStrictEqual(removed, ['stored-deleted']);
79
+ assert.equal(result.deletedMessages, 1);
80
+ });
81
+ //# sourceMappingURL=discord-history-delete-window.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discord-history-delete-window.test.js","sourceRoot":"","sources":["../../test/discord-history-delete-window.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=discord-history-sync.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discord-history-sync.test.d.ts","sourceRoot":"","sources":["../../test/discord-history-sync.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,56 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { DiscordModule } from '../src/modules/discord/index.js';
4
+ function historyMessage(id, content, timestamp) {
5
+ return {
6
+ id,
7
+ authorId: `author-${id}`,
8
+ authorName: `Author ${id}`,
9
+ isBot: false,
10
+ content,
11
+ timestamp: new Date(timestamp),
12
+ };
13
+ }
14
+ test('Discord history sync appends missed messages in chronological order', async () => {
15
+ const newestFirst = [
16
+ historyMessage('3', 'third', 3_000),
17
+ historyMessage('2', 'second', 2_000),
18
+ historyMessage('1', 'first', 1_000),
19
+ ];
20
+ const client = {
21
+ fetchHistory: async () => newestFirst,
22
+ };
23
+ const module = new DiscordModule(client, { token: 'test-token' });
24
+ const harness = module;
25
+ const added = [];
26
+ harness.ctx = {
27
+ queryMessages: () => ({ messages: [], totalCount: 0 }),
28
+ getAgents: () => [{ name: 'Sol' }],
29
+ addMessage: (_participant, content, metadata) => {
30
+ const text = content[0];
31
+ assert.ok(text && text.type === 'text' && typeof text.text === 'string');
32
+ const timestamp = metadata?.timestamp;
33
+ assert.ok(typeof timestamp === 'number');
34
+ added.push({
35
+ content: text.text,
36
+ timestamp,
37
+ });
38
+ return `stored-${added.length}`;
39
+ },
40
+ editMessage: () => { },
41
+ removeMessage: () => { },
42
+ };
43
+ const result = await harness.syncChannelHistory('channel-1');
44
+ assert.deepStrictEqual(added, [
45
+ { content: 'first', timestamp: 1_000 },
46
+ { content: 'second', timestamp: 2_000 },
47
+ { content: 'third', timestamp: 3_000 },
48
+ ]);
49
+ assert.deepStrictEqual(result, {
50
+ newMessages: 3,
51
+ editedMessages: 0,
52
+ deletedMessages: 0,
53
+ });
54
+ assert.equal(harness.state.lastReadMessageId['channel-1'], '3');
55
+ });
56
+ //# sourceMappingURL=discord-history-sync.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discord-history-sync.test.js","sourceRoot":"","sources":["../../test/discord-history-sync.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAkBhE,SAAS,cAAc,CAAC,EAAU,EAAE,OAAe,EAAE,SAAiB;IACpE,OAAO;QACL,EAAE;QACF,QAAQ,EAAE,UAAU,EAAE,EAAE;QACxB,UAAU,EAAE,UAAU,EAAE,EAAE;QAC1B,KAAK,EAAE,KAAK;QACZ,OAAO;QACP,SAAS,EAAE,IAAI,IAAI,CAAC,SAAS,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED,IAAI,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;IACrF,MAAM,WAAW,GAAG;QAClB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC;QACnC,cAAc,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC;QACpC,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC;KACpC,CAAC;IACF,MAAM,MAAM,GAAG;QACb,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC,WAAW;KACD,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,MAA0C,CAAC;IAC3D,MAAM,KAAK,GAAkD,EAAE,CAAC;IAEhE,OAAO,CAAC,GAAG,GAAG;QACZ,aAAa,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;QACtD,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAClC,UAAU,EAAE,CACV,YAAoB,EACpB,OAA+C,EAC/C,QAAiC,EACjC,EAAE;YACF,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACxB,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;YACzE,MAAM,SAAS,GAAG,QAAQ,EAAE,SAAS,CAAC;YACtC,MAAM,CAAC,EAAE,CAAC,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC;YACzC,KAAK,CAAC,IAAI,CAAC;gBACT,OAAO,EAAE,IAAI,CAAC,IAAI;gBAClB,SAAS;aACV,CAAC,CAAC;YACH,OAAO,UAAU,KAAK,CAAC,MAAM,EAAE,CAAC;QAClC,CAAC;QACD,WAAW,EAAE,GAAG,EAAE,GAAE,CAAC;QACrB,aAAa,EAAE,GAAG,EAAE,GAAE,CAAC;KACI,CAAC;IAE9B,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;IAE7D,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE;QAC5B,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE;QACtC,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE;QACvC,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE;KACvC,CAAC,CAAC;IACH,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE;QAC7B,WAAW,EAAE,CAAC;QACd,cAAc,EAAE,CAAC;QACjB,eAAe,EAAE,CAAC;KACnB,CAAC,CAAC;IACH,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * af#105 — intuitive wake-gate composition.
3
+ *
4
+ * Covers the four pieces that grew out of the 2026-08-08 Mythos
5
+ * stand-back-density incident (a prepended catch-all passive_sample silently
6
+ * made the DM/mention wake rules unreachable for the whole incoming lane):
7
+ *
8
+ * ① `passthrough` observer rules — non-firing counting behaviors fall
9
+ * through to later policies instead of consuming the event;
10
+ * ② shadow lint — provably-dead rules are reported at config time;
11
+ * ③ dry-run probes — side-effect-free "who would win" evaluation;
12
+ * ④ anchored positions — addPolicy({before}/{after}) placement.
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=event-gate-passthrough.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-gate-passthrough.test.d.ts","sourceRoot":"","sources":["../../test/event-gate-passthrough.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
@@ -0,0 +1,289 @@
1
+ /**
2
+ * af#105 — intuitive wake-gate composition.
3
+ *
4
+ * Covers the four pieces that grew out of the 2026-08-08 Mythos
5
+ * stand-back-density incident (a prepended catch-all passive_sample silently
6
+ * made the DM/mention wake rules unreachable for the whole incoming lane):
7
+ *
8
+ * ① `passthrough` observer rules — non-firing counting behaviors fall
9
+ * through to later policies instead of consuming the event;
10
+ * ② shadow lint — provably-dead rules are reported at config time;
11
+ * ③ dry-run probes — side-effect-free "who would win" evaluation;
12
+ * ④ anchored positions — addPolicy({before}/{after}) placement.
13
+ */
14
+ import { describe, it, beforeEach, afterEach } from 'node:test';
15
+ import assert from 'node:assert';
16
+ import { existsSync, mkdirSync, rmSync } from 'node:fs';
17
+ import { join } from 'node:path';
18
+ import { EventGate, findShadowedPolicies, formatShadowWarning } from '../src/gate/event-gate.js';
19
+ const TMP_DIR = join(import.meta.dirname, '../.test-tmp-gate-passthrough');
20
+ function makeGate(initialConfig) {
21
+ mkdirSync(TMP_DIR, { recursive: true });
22
+ const configPath = join(TMP_DIR, `gate-${Math.random().toString(36).slice(2)}.json`);
23
+ const traces = [];
24
+ const gate = new EventGate({
25
+ configPath,
26
+ initialConfig,
27
+ emitTrace: (e) => traces.push(e),
28
+ addMessage: () => '',
29
+ requestInference: () => { },
30
+ getAgentNames: () => ['agent'],
31
+ now: () => 1_000_000,
32
+ });
33
+ return { gate, configPath, traces };
34
+ }
35
+ function event(overrides) {
36
+ return {
37
+ content: 'test',
38
+ eventType: 'mcpl:channel-incoming',
39
+ serverId: 'discord',
40
+ channelId: 'discord:dm:1',
41
+ metadata: {},
42
+ ...overrides,
43
+ };
44
+ }
45
+ /** The Mythos incident's policy shapes, reusable across cases. */
46
+ const SAMPLER = {
47
+ name: 'stand-back-density',
48
+ match: { scope: ['mcpl:channel-incoming'] },
49
+ behavior: { passive_sample: { every: 3 } },
50
+ };
51
+ const DIRECT_ADDRESS = {
52
+ name: 'discord-direct-address',
53
+ match: { scope: ['mcpl:push-event', 'mcpl:channel-incoming'], metadataTrue: ['isMention', 'isDM'] },
54
+ behavior: 'always',
55
+ };
56
+ const AMBIENT = {
57
+ name: 'discord-ambient',
58
+ match: { scope: ['mcpl:push-event', 'mcpl:channel-incoming'] },
59
+ behavior: 'skip',
60
+ };
61
+ beforeEach(() => {
62
+ mkdirSync(TMP_DIR, { recursive: true });
63
+ });
64
+ afterEach(() => {
65
+ if (existsSync(TMP_DIR)) {
66
+ rmSync(TMP_DIR, { recursive: true, force: true });
67
+ }
68
+ });
69
+ // ---------------------------------------------------------------------------
70
+ // ① passthrough
71
+ // ---------------------------------------------------------------------------
72
+ describe('passthrough observer rules', () => {
73
+ it('non-firing passthrough sampler falls through to a later always rule (the incident, fixed)', () => {
74
+ const { gate } = makeGate({
75
+ policies: [
76
+ { ...SAMPLER, passthrough: true },
77
+ DIRECT_ADDRESS,
78
+ AMBIENT,
79
+ ],
80
+ default: 'skip',
81
+ });
82
+ // A DM: with the consuming sampler this was swallowed 149/150 times.
83
+ // With passthrough it must reach discord-direct-address every time the
84
+ // sampler doesn't fire.
85
+ const d1 = gate.evaluate(event({ metadata: { isDM: true } }));
86
+ assert.strictEqual(d1.trigger, true);
87
+ assert.strictEqual(d1.policyName, 'discord-direct-address');
88
+ assert.deepStrictEqual(d1.observed, ['stand-back-density']);
89
+ });
90
+ it('passthrough sampler still fires every Nth match, and consumes on fire', () => {
91
+ const { gate } = makeGate({
92
+ policies: [{ ...SAMPLER, passthrough: true }, AMBIENT],
93
+ default: 'skip',
94
+ });
95
+ // every:3 — two ambient events fall through to the ambient skip, the
96
+ // third fires the sampler itself.
97
+ const d1 = gate.evaluate(event());
98
+ const d2 = gate.evaluate(event());
99
+ const d3 = gate.evaluate(event());
100
+ assert.strictEqual(d1.trigger, false);
101
+ assert.strictEqual(d1.policyName, 'discord-ambient');
102
+ assert.strictEqual(d2.policyName, 'discord-ambient');
103
+ assert.strictEqual(d3.trigger, true);
104
+ assert.strictEqual(d3.policyName, 'stand-back-density');
105
+ assert.strictEqual(d3.observed, undefined);
106
+ });
107
+ it('counts every matching event even when a later rule wakes anyway', () => {
108
+ const { gate } = makeGate({
109
+ policies: [{ ...SAMPLER, passthrough: true }, DIRECT_ADDRESS, AMBIENT],
110
+ default: 'skip',
111
+ });
112
+ // Two DMs (wake via direct-address, sampler counts both), then one
113
+ // ambient event: sampler is at 2, the ambient event is its 3rd → fires.
114
+ gate.evaluate(event({ metadata: { isDM: true } }));
115
+ gate.evaluate(event({ metadata: { isDM: true } }));
116
+ const d3 = gate.evaluate(event());
117
+ assert.strictEqual(d3.trigger, true);
118
+ assert.strictEqual(d3.policyName, 'stand-back-density');
119
+ });
120
+ it('falls through to the gate default when nothing later matches', () => {
121
+ const { gate } = makeGate({
122
+ policies: [{ ...SAMPLER, passthrough: true }],
123
+ default: 'skip',
124
+ });
125
+ const d = gate.evaluate(event());
126
+ assert.strictEqual(d.trigger, false);
127
+ assert.strictEqual(d.policyName, null);
128
+ assert.deepStrictEqual(d.observed, ['stand-back-density']);
129
+ // The fall-to-default is counted in default decision stats.
130
+ assert.strictEqual(gate.getStatus().defaultDecisions.skipped, 1);
131
+ });
132
+ it('rejects passthrough on non-counting behaviors', () => {
133
+ for (const behavior of ['always', 'skip', { debounce: 1000 }]) {
134
+ const { gate } = makeGate({
135
+ policies: [{ name: 'p', match: {}, behavior, passthrough: true }],
136
+ });
137
+ const errors = gate.getStatus().errors;
138
+ assert.ok(errors.some((e) => /passthrough is only valid/.test(e)), `expected passthrough validation error for ${JSON.stringify(behavior)}, got: ${JSON.stringify(errors)}`);
139
+ }
140
+ });
141
+ it('accepts passthrough on rate_limit and falls through when the bucket is empty', () => {
142
+ const { gate } = makeGate({
143
+ policies: [
144
+ {
145
+ name: 'burst-governor',
146
+ match: {},
147
+ behavior: { rate_limit: { tokens: 1, refillIntervalMs: 60_000 } },
148
+ passthrough: true,
149
+ },
150
+ { name: 'catch-all', match: {}, behavior: 'skip' },
151
+ ],
152
+ default: 'always',
153
+ });
154
+ const d1 = gate.evaluate(event());
155
+ assert.strictEqual(d1.trigger, true); // token available → fires
156
+ const d2 = gate.evaluate(event());
157
+ assert.strictEqual(d2.trigger, false); // bucket empty → falls through
158
+ assert.strictEqual(d2.policyName, 'catch-all');
159
+ assert.deepStrictEqual(d2.observed, ['burst-governor']);
160
+ });
161
+ });
162
+ // ---------------------------------------------------------------------------
163
+ // ② shadow lint
164
+ // ---------------------------------------------------------------------------
165
+ describe('shadow lint', () => {
166
+ it('flags the incident shape: prepended scope catch-all shadows direct-address for the overlapped scope', () => {
167
+ const warnings = findShadowedPolicies([SAMPLER, DIRECT_ADDRESS, AMBIENT]);
168
+ const hit = warnings.find((w) => w.later === 'discord-direct-address');
169
+ assert.ok(hit, `expected direct-address shadow warning, got ${JSON.stringify(warnings)}`);
170
+ assert.strictEqual(hit.earlier, 'stand-back-density');
171
+ assert.deepStrictEqual(hit.eventTypes, ['mcpl:channel-incoming']);
172
+ assert.match(formatShadowWarning(hit), /unreachable for mcpl:channel-incoming/);
173
+ });
174
+ it('a passthrough observer shadows nothing', () => {
175
+ const warnings = findShadowedPolicies([
176
+ { ...SAMPLER, passthrough: true },
177
+ DIRECT_ADDRESS,
178
+ AMBIENT,
179
+ ]);
180
+ assert.ok(!warnings.some((w) => w.earlier === 'stand-back-density'));
181
+ });
182
+ it('does not flag rules the earlier one cannot fully cover', () => {
183
+ // direct-address has a metadataTrue discriminator ambient lacks: events
184
+ // with no truthy flags slip past it, so ambient stays reachable.
185
+ const warnings = findShadowedPolicies([DIRECT_ADDRESS, AMBIENT]);
186
+ assert.deepStrictEqual(warnings, []);
187
+ });
188
+ it('subset metadataTrue IS flagged (earlier OR-list covers later)', () => {
189
+ const warnings = findShadowedPolicies([
190
+ { name: 'broad', match: { metadataTrue: ['isMention', 'isDM'] }, behavior: 'skip' },
191
+ { name: 'narrow', match: { metadataTrue: ['isDM'] }, behavior: 'always' },
192
+ ]);
193
+ assert.strictEqual(warnings.length, 1);
194
+ assert.strictEqual(warnings[0].later, 'narrow');
195
+ assert.strictEqual(warnings[0].eventTypes, 'all');
196
+ });
197
+ it('surfaces via gate:shadow-warnings trace and getStatus on mutation', () => {
198
+ const { gate, traces } = makeGate({ policies: [DIRECT_ADDRESS, AMBIENT], default: 'skip' });
199
+ assert.deepStrictEqual(gate.getStatus().shadowWarnings, []);
200
+ gate.addPolicy(SAMPLER, { position: 'prepend' });
201
+ const status = gate.getStatus();
202
+ assert.ok(status.shadowWarnings.some((w) => /discord-direct-address/.test(w)), `expected shadow warning in status, got ${JSON.stringify(status.shadowWarnings)}`);
203
+ assert.ok(traces.some((t) => t.type === 'gate:shadow-warnings'));
204
+ });
205
+ });
206
+ // ---------------------------------------------------------------------------
207
+ // ③ dry-run probes
208
+ // ---------------------------------------------------------------------------
209
+ describe('dry-run probes', () => {
210
+ it('probe reports the winner without advancing counters', () => {
211
+ const { gate } = makeGate({ policies: [SAMPLER, DIRECT_ADDRESS], default: 'skip' });
212
+ // Probe the same DM three times — a MUTATING evaluate would fire the
213
+ // every:3 sampler on the third call; probes must not.
214
+ for (let i = 0; i < 3; i++) {
215
+ const p = gate.probe(event({ metadata: { isDM: true } }));
216
+ assert.strictEqual(p.policyName, 'stand-back-density');
217
+ assert.strictEqual(p.trigger, false);
218
+ }
219
+ // Real evaluation still starts from a cold counter.
220
+ const d = gate.evaluate(event({ metadata: { isDM: true } }));
221
+ assert.strictEqual(d.trigger, false);
222
+ });
223
+ it('probe honors passthrough fall-through', () => {
224
+ const { gate } = makeGate({
225
+ policies: [{ ...SAMPLER, passthrough: true }, DIRECT_ADDRESS],
226
+ default: 'skip',
227
+ });
228
+ const p = gate.probe(event({ metadata: { isDM: true } }));
229
+ assert.strictEqual(p.policyName, 'discord-direct-address');
230
+ assert.strictEqual(p.trigger, true);
231
+ });
232
+ it('probeTable makes the incident visible as a changed dm row', () => {
233
+ const { gate } = makeGate({ policies: [DIRECT_ADDRESS, AMBIENT], default: 'skip' });
234
+ const before = gate.probeTable();
235
+ const dmBefore = before.find((r) => r.probe === 'dm (open channel)');
236
+ assert.ok(dmBefore);
237
+ assert.strictEqual(dmBefore.policy, 'discord-direct-address');
238
+ assert.strictEqual(dmBefore.wouldWake, true);
239
+ gate.addPolicy(SAMPLER, { position: 'prepend' });
240
+ const after = gate.probeTable();
241
+ const dmAfter = after.find((r) => r.probe === 'dm (open channel)');
242
+ assert.ok(dmAfter);
243
+ assert.strictEqual(dmAfter.policy, 'stand-back-density');
244
+ assert.strictEqual(dmAfter.wouldWake, false);
245
+ // The closed-channel (push/event) dm row is untouched — exactly the
246
+ // asymmetry that made the incident look intermittent.
247
+ const dmPush = after.find((r) => r.probe === 'dm (closed channel)');
248
+ assert.ok(dmPush);
249
+ assert.strictEqual(dmPush.policy, 'discord-direct-address');
250
+ assert.strictEqual(dmPush.wouldWake, true);
251
+ });
252
+ });
253
+ // ---------------------------------------------------------------------------
254
+ // ④ anchored positions
255
+ // ---------------------------------------------------------------------------
256
+ describe('anchored positions', () => {
257
+ it('inserts before/after a named anchor', () => {
258
+ const { gate } = makeGate({ policies: [DIRECT_ADDRESS, AMBIENT], default: 'skip' });
259
+ gate.addPolicy(SAMPLER, { position: { before: 'discord-ambient' } });
260
+ assert.deepStrictEqual(gate.listPolicyNames(), [
261
+ 'discord-direct-address', 'stand-back-density', 'discord-ambient',
262
+ ]);
263
+ gate.addPolicy({ name: 'after-anchor', match: {}, behavior: 'skip' }, { position: { after: 'discord-direct-address' } });
264
+ assert.deepStrictEqual(gate.listPolicyNames(), [
265
+ 'discord-direct-address', 'after-anchor', 'stand-back-density', 'discord-ambient',
266
+ ]);
267
+ });
268
+ it('throws on a missing anchor, naming the available rules', () => {
269
+ const { gate } = makeGate({ policies: [AMBIENT], default: 'skip' });
270
+ assert.throws(() => gate.addPolicy(SAMPLER, { position: { before: 'no-such-rule' } }), /no policy named "no-such-rule".*discord-ambient/s);
271
+ });
272
+ it('replacement without a position stays in place; with a position it moves', () => {
273
+ const { gate } = makeGate({
274
+ policies: [SAMPLER, DIRECT_ADDRESS, AMBIENT],
275
+ default: 'skip',
276
+ });
277
+ // In-place update keeps the (bad) prepended slot.
278
+ gate.addPolicy({ ...SAMPLER, behavior: { passive_sample: { every: 5 } } });
279
+ assert.deepStrictEqual(gate.listPolicyNames(), [
280
+ 'stand-back-density', 'discord-direct-address', 'discord-ambient',
281
+ ]);
282
+ // Re-issuing WITH an anchor is the repair path for the incident.
283
+ gate.addPolicy(SAMPLER, { position: { before: 'discord-ambient' } });
284
+ assert.deepStrictEqual(gate.listPolicyNames(), [
285
+ 'discord-direct-address', 'stand-back-density', 'discord-ambient',
286
+ ]);
287
+ });
288
+ });
289
+ //# sourceMappingURL=event-gate-passthrough.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-gate-passthrough.test.js","sourceRoot":"","sources":["../../test/event-gate-passthrough.test.ts"],"names":[],"mappings":"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"}