instar 1.3.655 → 1.3.657

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 (40) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +21 -0
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/core/LiveTestHarness.d.ts +55 -1
  5. package/dist/core/LiveTestHarness.d.ts.map +1 -1
  6. package/dist/core/LiveTestHarness.js +71 -2
  7. package/dist/core/LiveTestHarness.js.map +1 -1
  8. package/dist/core/RealChannelDriver.d.ts +15 -0
  9. package/dist/core/RealChannelDriver.d.ts.map +1 -1
  10. package/dist/core/RealChannelDriver.js +16 -0
  11. package/dist/core/RealChannelDriver.js.map +1 -1
  12. package/dist/core/SlackLiveSender.d.ts +29 -0
  13. package/dist/core/SlackLiveSender.d.ts.map +1 -1
  14. package/dist/core/SlackLiveSender.js +68 -3
  15. package/dist/core/SlackLiveSender.js.map +1 -1
  16. package/dist/core/TelegramLiveSender.d.ts +18 -0
  17. package/dist/core/TelegramLiveSender.d.ts.map +1 -1
  18. package/dist/core/TelegramLiveSender.js +60 -0
  19. package/dist/core/TelegramLiveSender.js.map +1 -1
  20. package/dist/core/rateLimitFalsePositiveMatrix.d.ts +28 -0
  21. package/dist/core/rateLimitFalsePositiveMatrix.d.ts.map +1 -0
  22. package/dist/core/rateLimitFalsePositiveMatrix.js +74 -0
  23. package/dist/core/rateLimitFalsePositiveMatrix.js.map +1 -0
  24. package/dist/monitoring/CompactionSentinel.d.ts +9 -0
  25. package/dist/monitoring/CompactionSentinel.d.ts.map +1 -1
  26. package/dist/monitoring/CompactionSentinel.js +8 -0
  27. package/dist/monitoring/CompactionSentinel.js.map +1 -1
  28. package/dist/monitoring/QuotaCollector.d.ts.map +1 -1
  29. package/dist/monitoring/QuotaCollector.js +21 -8
  30. package/dist/monitoring/QuotaCollector.js.map +1 -1
  31. package/dist/monitoring/RateLimitSentinel.d.ts +25 -0
  32. package/dist/monitoring/RateLimitSentinel.d.ts.map +1 -1
  33. package/dist/monitoring/RateLimitSentinel.js +44 -0
  34. package/dist/monitoring/RateLimitSentinel.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/data/builtin-manifest.json +2 -2
  37. package/upgrades/1.3.656.md +68 -0
  38. package/upgrades/1.3.657.md +32 -0
  39. package/upgrades/side-effects/false-ratelimit-recovery-completed-sessions.md +113 -0
  40. package/upgrades/side-effects/real-channel-absence-collect.md +73 -0
@@ -39,6 +39,45 @@ export interface ChannelDriver {
39
39
  timeoutMs: number;
40
40
  afterMessageId?: string;
41
41
  }): Promise<ReplyResult | null>;
42
+ /**
43
+ * OPTIONAL — collect EVERY message that lands on the channel within a window
44
+ * (after `afterMessageId`). Backs ABSENCE assertions: "after X, no message
45
+ * matching <pattern> arrives within the window". A single awaitReply can't prove
46
+ * absence (it returns the first reply, and a spurious background nudge may land
47
+ * AFTER a legitimate reply). A driver that does not implement this makes an
48
+ * absence scenario BLOCKED (driver-unsupported), never a silent pass. The fix
49
+ * this enables to test: a finished session must emit ZERO throttle-resume nudges
50
+ * (live incident 2026-06-24).
51
+ */
52
+ collectMessages?(surface: Surface, channelId: string, opts: {
53
+ windowMs: number;
54
+ afterMessageId?: string;
55
+ }): Promise<ReplyResult[]>;
56
+ }
57
+ /**
58
+ * Thrown by a driver whose `collectMessages` exists at the object level but cannot
59
+ * serve a SPECIFIC surface (e.g. RealChannelDriver implements collectMessages, but the
60
+ * sender wired for `dashboard` has no history to collect). The harness maps THIS error
61
+ * to BLOCKED (driver-unsupported) rather than FAIL — an absence assertion the driver
62
+ * genuinely cannot make on this surface is unverifiable, not a failure. Any OTHER throw
63
+ * remains a loud FAIL (a real driver error must not be silently downgraded).
64
+ */
65
+ export declare class DriverCapabilityError extends Error {
66
+ constructor(message: string);
67
+ }
68
+ /**
69
+ * Thrown by a SENDER's `collectMessages` when it read the channel but CANNOT guarantee
70
+ * it saw every message in the window — a paginated/truncated history read (a full page
71
+ * came back, so more may exist) or a failed read. An absence proof over an incomplete
72
+ * read would silently false-PASS (the spurious nudge could be on the page we never
73
+ * fetched), so the harness maps THIS to BLOCKED, never PASS. Distinct from
74
+ * DriverCapabilityError (which is the capability LAYER saying a surface has no collector
75
+ * at all): senders raise THIS for an incomplete read; only RealChannelDriver raises
76
+ * DriverCapabilityError for a missing method. A real transport error stays a plain Error
77
+ * (→ FAIL).
78
+ */
79
+ export declare class AbsenceUnverifiableError extends Error {
80
+ constructor(message: string);
42
81
  }
43
82
  export type Volatility = 'safe' | 'volatile' | 'permission';
44
83
  export interface HarnessScenario {
@@ -50,12 +89,27 @@ export interface HarnessScenario {
50
89
  channelId: string;
51
90
  /** The user message to send. */
52
91
  input: string;
53
- /** Deterministic expectations checked against the captured reply. */
92
+ /**
93
+ * Deterministic expectations checked against the captured reply (or, for an
94
+ * absence scenario, against every message collected over `absenceWindowMs`).
95
+ * - replyContains / replyNotEmpty / responderMachine: assert the reply.
96
+ * - replyMustNotContain: the (first) reply must NOT contain this substring.
97
+ * - noMessageMatching: ABSENCE — paired with `absenceWindowMs`, asserts NO
98
+ * message landing on the channel within the window contains this substring.
99
+ */
54
100
  expect: {
55
101
  replyContains?: string;
56
102
  replyNotEmpty?: boolean;
57
103
  responderMachine?: string;
104
+ replyMustNotContain?: string;
105
+ noMessageMatching?: string;
58
106
  };
107
+ /**
108
+ * When set, this is an ABSENCE scenario: after sending `input`, the harness
109
+ * collects every message on the channel for this many ms and asserts none match
110
+ * `expect.noMessageMatching`. Requires a driver implementing `collectMessages`.
111
+ */
112
+ absenceWindowMs?: number;
59
113
  timeoutMs?: number;
60
114
  }
61
115
  export interface HarnessMatrix {
@@ -1 +1 @@
1
- {"version":3,"file":"LiveTestHarness.d.ts","sourceRoot":"","sources":["../../src/core/LiveTestHarness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAAE,qBAAqB,EAAE,YAAY,EAAe,OAAO,EAC5E,MAAM,4BAA4B,CAAC;AAEpC,MAAM,WAAW,UAAU;IAAG,SAAS,EAAE,MAAM,CAAA;CAAE;AACjD,MAAM,WAAW,WAAW;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE;AAE7F,kFAAkF;AAClF,MAAM,WAAW,aAAa;IAC5B,kFAAkF;IAClF,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5D,+CAA+C;IAC/C,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7E,0DAA0D;IAC1D,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CACpI;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,MAAM,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,SAAS,EAAE,eAAe,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,qBAAqB,CAAC;IAC7B,MAAM,EAAE,aAAa,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kFAAkF;IAClF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,qBAAa,2BAA4B,SAAQ,KAAK;gBACxC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM;CAIpE;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAsB;gBAE5B,IAAI,EAAE,mBAAmB;IAIrC,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,GAAG;IAEX;;;;;OAKG;IACG,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,gBAAgB,CAAC;QAAC,KAAK,EAAE,UAAU,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAA;KAAE,CAAC;YA4B7I,WAAW;CA+B1B"}
1
+ {"version":3,"file":"LiveTestHarness.d.ts","sourceRoot":"","sources":["../../src/core/LiveTestHarness.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,31 @@
19
19
  * platform), not a fuzzy judgment. (An optional Tier-1 semantic supervisor for
20
20
  * natural-language expectations is a follow-on; the core encodes exact checks.)
21
21
  */
22
+ /**
23
+ * Thrown by a driver whose `collectMessages` exists at the object level but cannot
24
+ * serve a SPECIFIC surface (e.g. RealChannelDriver implements collectMessages, but the
25
+ * sender wired for `dashboard` has no history to collect). The harness maps THIS error
26
+ * to BLOCKED (driver-unsupported) rather than FAIL — an absence assertion the driver
27
+ * genuinely cannot make on this surface is unverifiable, not a failure. Any OTHER throw
28
+ * remains a loud FAIL (a real driver error must not be silently downgraded).
29
+ */
30
+ export class DriverCapabilityError extends Error {
31
+ constructor(message) { super(message); this.name = 'DriverCapabilityError'; }
32
+ }
33
+ /**
34
+ * Thrown by a SENDER's `collectMessages` when it read the channel but CANNOT guarantee
35
+ * it saw every message in the window — a paginated/truncated history read (a full page
36
+ * came back, so more may exist) or a failed read. An absence proof over an incomplete
37
+ * read would silently false-PASS (the spurious nudge could be on the page we never
38
+ * fetched), so the harness maps THIS to BLOCKED, never PASS. Distinct from
39
+ * DriverCapabilityError (which is the capability LAYER saying a surface has no collector
40
+ * at all): senders raise THIS for an incomplete read; only RealChannelDriver raises
41
+ * DriverCapabilityError for a missing method. A real transport error stays a plain Error
42
+ * (→ FAIL).
43
+ */
44
+ export class AbsenceUnverifiableError extends Error {
45
+ constructor(message) { super(message); this.name = 'AbsenceUnverifiableError'; }
46
+ }
22
47
  export class HarnessVolatileChannelError extends Error {
23
48
  constructor(scenarioId, surface, channelId) {
24
49
  super(`refusing volatile/permission scenario "${scenarioId}" on non-demo channel ${surface}:${channelId} (§5.3 — volatile scenarios run only on demo channels)`);
@@ -40,9 +65,13 @@ export class LiveTestHarness {
40
65
  */
41
66
  async run(matrix, opts = {}) {
42
67
  // §5.3 PRE-FLIGHT: refuse the whole run if a volatile/permission scenario points
43
- // at a non-demo channel — before a single message is sent.
68
+ // at a non-demo channel — before a single message is sent. An ABSENCE scenario
69
+ // (absenceWindowMs != null) is ALSO demo-only regardless of its `safe` tag: it polls
70
+ // the channel's whole agent-outbound history into the harness/logs, so a `safe` tag
71
+ // must not let it read a live (operator) channel's content (security review FD-2).
44
72
  for (const s of matrix.scenarios) {
45
- if (s.volatility !== 'safe' && !this.d.driver.isDemoChannel(s.surface, s.channelId)) {
73
+ const requiresDemo = s.volatility !== 'safe' || s.absenceWindowMs != null;
74
+ if (requiresDemo && !this.d.driver.isDemoChannel(s.surface, s.channelId)) {
46
75
  throw new HarnessVolatileChannelError(s.id, s.surface, s.channelId);
47
76
  }
48
77
  }
@@ -67,6 +96,44 @@ export class LiveTestHarness {
67
96
  const timeoutMs = s.timeoutMs ?? this.d.defaultTimeoutMs ?? 30_000;
68
97
  const maxRetries = this.d.maxReplyRetries ?? 2;
69
98
  const base = { id: s.id, description: s.description, surface: s.surface, riskCategory: s.riskCategory, verdict: 'FAIL' };
99
+ // ── ABSENCE scenario: assert NO message matching the pattern lands within the
100
+ // window (the structural way to catch a spurious background message — e.g. a
101
+ // throttle-resume nudge fired against a finished session).
102
+ if (s.absenceWindowMs != null) {
103
+ const pattern = s.expect.noMessageMatching;
104
+ if (!pattern) {
105
+ return { ...base, verdict: 'BLOCKED', blockedKind: 'operator-waiver', blockedReason: 'absence scenario missing expect.noMessageMatching' };
106
+ }
107
+ if (!this.d.driver.collectMessages) {
108
+ // Never silently pass — an absence assertion an unsupported driver cannot
109
+ // make is BLOCKED with a named reason, not a PASS.
110
+ return { ...base, verdict: 'BLOCKED', blockedKind: 'platform-error', blockedReason: 'driver does not support collectMessages (absence assertion unverifiable)' };
111
+ }
112
+ try {
113
+ const sent = await this.d.driver.send(s.surface, s.channelId, s.input);
114
+ const collected = await this.d.driver.collectMessages(s.surface, s.channelId, { windowMs: s.absenceWindowMs, afterMessageId: sent.messageId });
115
+ const offending = collected.find(m => m.text.includes(pattern));
116
+ const evidence = { channelId: s.channelId, messageIds: [sent.messageId, ...collected.map(m => m.messageId)] };
117
+ if (offending) {
118
+ this.log(`scenario ${s.id} FAIL: spurious message matched "${pattern}": ${JSON.stringify(offending.text.slice(0, 120))}`);
119
+ return { ...base, verdict: 'FAIL', evidence, blockedReason: `spurious message matched "${pattern}"` };
120
+ }
121
+ return { ...base, verdict: 'PASS', evidence };
122
+ }
123
+ catch (err) {
124
+ if (err instanceof DriverCapabilityError || err instanceof AbsenceUnverifiableError) {
125
+ // Either the surface has no collector (DriverCapabilityError) or the read could
126
+ // not be proven complete (AbsenceUnverifiableError — truncated/paginated/failed
127
+ // history). Both make the absence assertion unverifiable → BLOCKED (named),
128
+ // never a silent PASS over an incomplete read and never a misleading FAIL.
129
+ return { ...base, verdict: 'BLOCKED', blockedKind: 'platform-error', blockedReason: `absence unverifiable on surface "${s.surface}": ${err.message}` };
130
+ }
131
+ // @silent-fallback-ok: not a silent fallback — a real driver error is SURFACED as
132
+ // a FAIL verdict (with the error in blockedReason) that the LiveTestGate consumes
133
+ // and VETOES on. The error is escalated, not swallowed; this is the loud path.
134
+ return { ...base, verdict: 'FAIL', blockedReason: `driver error: ${err instanceof Error ? err.message : String(err)}` };
135
+ }
136
+ }
70
137
  try {
71
138
  const sent = await this.d.driver.send(s.surface, s.channelId, s.input);
72
139
  let reply = null;
@@ -85,6 +152,8 @@ export class LiveTestHarness {
85
152
  failures.push(`reply missing "${s.expect.replyContains}"`);
86
153
  if (s.expect.replyNotEmpty && reply.text.trim() === '')
87
154
  failures.push('reply empty');
155
+ if (s.expect.replyMustNotContain && reply.text.includes(s.expect.replyMustNotContain))
156
+ failures.push(`reply unexpectedly contained "${s.expect.replyMustNotContain}"`);
88
157
  if (s.expect.responderMachine && reply.responderMachineId !== s.expect.responderMachine)
89
158
  failures.push(`responder ${reply.responderMachineId ?? 'unknown'} ≠ expected ${s.expect.responderMachine}`);
90
159
  if (failures.length) {
@@ -1 +1 @@
1
- {"version":3,"file":"LiveTestHarness.js","sourceRoot":"","sources":["../../src/core/LiveTestHarness.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LiveTestHarness.js","sourceRoot":"","sources":["../../src/core/LiveTestHarness.ts"],"names":[],"mappings":"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"}
@@ -32,6 +32,17 @@ export interface SurfaceSender {
32
32
  timeoutMs: number;
33
33
  afterMessageId?: string;
34
34
  }): Promise<Omit<ReplyResult, 'responderMachineId'> | null>;
35
+ /**
36
+ * OPTIONAL — collect EVERY agent-authored message on the channel within `windowMs`
37
+ * after `afterMessageId` (the surface's OUTBOUND, the class a spurious background
38
+ * nudge belongs to). Backs the harness ABSENCE assertion over a REAL channel. A
39
+ * sender that omits this makes its surface unverifiable for absence (the driver
40
+ * raises DriverCapabilityError → harness BLOCKED, never a false PASS).
41
+ */
42
+ collectMessages?(channelId: string, opts: {
43
+ windowMs: number;
44
+ afterMessageId?: string;
45
+ }): Promise<Array<Omit<ReplyResult, 'responderMachineId'>>>;
35
46
  }
36
47
  export interface RealChannelDriverDeps {
37
48
  /** Per-surface real senders. A surface absent here throws if a scenario targets it. */
@@ -57,5 +68,9 @@ export declare class RealChannelDriver implements ChannelDriver {
57
68
  timeoutMs: number;
58
69
  afterMessageId?: string;
59
70
  }): Promise<ReplyResult | null>;
71
+ collectMessages(surface: Surface, channelId: string, opts: {
72
+ windowMs: number;
73
+ afterMessageId?: string;
74
+ }): Promise<ReplyResult[]>;
60
75
  }
61
76
  //# sourceMappingURL=RealChannelDriver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RealChannelDriver.d.ts","sourceRoot":"","sources":["../../src/core/RealChannelDriver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,kGAAkG;AAClG,MAAM,WAAW,aAAa;IAC5B,oDAAoD;IACpD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3D,kHAAkH;IAClH,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,GAAG,IAAI,CAAC,CAAC;CAC9I;AAED,MAAM,WAAW,qBAAqB;IACpC,uFAAuF;IACvF,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;IACjD,mCAAmC;IACnC,YAAY,EAAE,IAAI,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC;IACzD;;;;OAIG;IACH,uBAAuB,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzF,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,qBAAa,iBAAkB,YAAW,aAAa;IACrD,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAwB;gBAC9B,IAAI,EAAE,qBAAqB;IAEvC,OAAO,CAAC,GAAG;IAEX,OAAO,CAAC,SAAS;IAUjB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAIrD,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAI5E,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;CAezI"}
1
+ {"version":3,"file":"RealChannelDriver.d.ts","sourceRoot":"","sources":["../../src/core/RealChannelDriver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,kGAAkG;AAClG,MAAM,WAAW,aAAa;IAC5B,oDAAoD;IACpD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3D,kHAAkH;IAClH,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,GAAG,IAAI,CAAC,CAAC;IAC7I;;;;;;OAMG;IACH,eAAe,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAAC;CACnJ;AAED,MAAM,WAAW,qBAAqB;IACpC,uFAAuF;IACvF,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;IACjD,mCAAmC;IACnC,YAAY,EAAE,IAAI,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC;IACzD;;;;OAIG;IACH,uBAAuB,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzF,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,qBAAa,iBAAkB,YAAW,aAAa;IACrD,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAwB;gBAC9B,IAAI,EAAE,qBAAqB;IAEvC,OAAO,CAAC,GAAG;IAEX,OAAO,CAAC,SAAS;IAUjB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAIrD,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAI5E,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAgBlI,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;CAexI"}
@@ -20,6 +20,7 @@
20
20
  * failures degrade to `undefined` (the harness then simply can't assert on responder)
21
21
  * rather than throwing the whole scenario — the SEND/REPLY evidence is still recorded.
22
22
  */
23
+ import { DriverCapabilityError } from './LiveTestHarness.js';
23
24
  export class RealChannelDriver {
24
25
  d;
25
26
  constructor(deps) { this.d = deps; }
@@ -56,5 +57,20 @@ export class RealChannelDriver {
56
57
  }
57
58
  return { ...reply, responderMachineId };
58
59
  }
60
+ async collectMessages(surface, channelId, opts) {
61
+ const sender = this.senderFor(surface);
62
+ if (!sender.collectMessages) {
63
+ // The surface is wired, but its sender can't collect history — the absence
64
+ // assertion is unverifiable HERE. Raise the typed capability error so the harness
65
+ // records BLOCKED (driver-unsupported), never a false PASS and never a FAIL that
66
+ // would wrongly read as "the agent sent a spurious message".
67
+ throw new DriverCapabilityError(`sender for surface "${surface}" does not implement collectMessages`);
68
+ }
69
+ const msgs = await sender.collectMessages(channelId, opts);
70
+ // The absence assertion checks message TEXT only; responder-machine attribution is
71
+ // unnecessary here (and would cost one placement read per message). Return the
72
+ // agent-authored messages as ReplyResult with responderMachineId left undefined.
73
+ return msgs.map(m => ({ ...m }));
74
+ }
59
75
  }
60
76
  //# sourceMappingURL=RealChannelDriver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RealChannelDriver.js","sourceRoot":"","sources":["../../src/core/RealChannelDriver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AA4BH,MAAM,OAAO,iBAAiB;IACX,CAAC,CAAwB;IAC1C,YAAY,IAA2B,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IAEnD,GAAG,CAAC,CAAS,IAAU,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAEvE,SAAS,CAAC,OAAgB;QAChC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,8EAA8E;YAC9E,kEAAkE;YAClE,MAAM,IAAI,KAAK,CAAC,0CAA0C,OAAO,qBAAqB,CAAC,CAAC;QAC1F,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,aAAa,CAAC,OAAgB,EAAE,SAAiB;QAC/C,OAAO,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAgB,EAAE,SAAiB,EAAE,IAAY;QAC1D,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAAgB,EAAE,SAAiB,EAAE,IAAoD;QACxG,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACxE,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,kBAAsC,CAAC;QAC3C,IAAI,CAAC;YACH,kBAAkB,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,uBAAuB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC;QAC/F,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,gFAAgF;YAChF,2EAA2E;YAC3E,6DAA6D;YAC7D,IAAI,CAAC,GAAG,CAAC,wCAAwC,OAAO,IAAI,SAAS,kCAAkC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3J,kBAAkB,GAAG,SAAS,CAAC;QACjC,CAAC;QACD,OAAO,EAAE,GAAG,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC1C,CAAC;CACF"}
1
+ {"version":3,"file":"RealChannelDriver.js","sourceRoot":"","sources":["../../src/core/RealChannelDriver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAmC7D,MAAM,OAAO,iBAAiB;IACX,CAAC,CAAwB;IAC1C,YAAY,IAA2B,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IAEnD,GAAG,CAAC,CAAS,IAAU,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAEvE,SAAS,CAAC,OAAgB;QAChC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,8EAA8E;YAC9E,kEAAkE;YAClE,MAAM,IAAI,KAAK,CAAC,0CAA0C,OAAO,qBAAqB,CAAC,CAAC;QAC1F,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,aAAa,CAAC,OAAgB,EAAE,SAAiB;QAC/C,OAAO,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAgB,EAAE,SAAiB,EAAE,IAAY;QAC1D,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAAgB,EAAE,SAAiB,EAAE,IAAoD;QACxG,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACxE,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,kBAAsC,CAAC;QAC3C,IAAI,CAAC;YACH,kBAAkB,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,uBAAuB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC;QAC/F,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,gFAAgF;YAChF,2EAA2E;YAC3E,6DAA6D;YAC7D,IAAI,CAAC,GAAG,CAAC,wCAAwC,OAAO,IAAI,SAAS,kCAAkC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3J,kBAAkB,GAAG,SAAS,CAAC;QACjC,CAAC;QACD,OAAO,EAAE,GAAG,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,OAAgB,EAAE,SAAiB,EAAE,IAAmD;QAC5G,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YAC5B,2EAA2E;YAC3E,kFAAkF;YAClF,iFAAiF;YACjF,6DAA6D;YAC7D,MAAM,IAAI,qBAAqB,CAAC,uBAAuB,OAAO,sCAAsC,CAAC,CAAC;QACxG,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAC3D,mFAAmF;QACnF,+EAA+E;QAC/E,iFAAiF;QACjF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACnC,CAAC;CACF"}
@@ -41,6 +41,14 @@ export interface SlackLiveSenderDeps {
41
41
  api: SlackCaller;
42
42
  /** The agent's (Echo's) Slack bot user id — awaitReply waits for a reply authored by THIS id. */
43
43
  agentBotUserId: string;
44
+ /**
45
+ * OPTIONAL — the agent's Slack app `bot_id`. A message posted by the agent's BACKGROUND
46
+ * path (incoming-webhook / app post) can carry `bot_id` with NO `user` field; matching
47
+ * on `agentBotUserId` alone would then SKIP it → a spurious background nudge would be
48
+ * missed by the absence proof (false PASS). When set, a message authored by EITHER the
49
+ * agent's user id OR this bot_id counts as agent-outbound. (Lessons-review FD-3.)
50
+ */
51
+ agentBotId?: string;
44
52
  /** Poll cadence while awaiting a reply. Default 2000ms. */
45
53
  pollIntervalMs?: number;
46
54
  /** Injected for tests; defaults to real timers / clock. */
@@ -59,6 +67,27 @@ export declare class SlackLiveSender implements SurfaceSender {
59
67
  timeoutMs: number;
60
68
  afterMessageId?: string;
61
69
  }): Promise<Omit<ReplyResult, 'responderMachineId'> | null>;
70
+ /** A message is agent-outbound if it is from the agent's user id OR its app bot_id. */
71
+ private isAgentAuthored;
72
+ /**
73
+ * Collect EVERY agent-authored message strictly after `after`, polling across the
74
+ * window so a nudge landing LATE (after a legitimate reply) is still seen. Returned
75
+ * oldest-first. Backs the absence assertion over a real Slack channel.
76
+ *
77
+ * Soundness for an ABSENCE proof (an under-collection here is a silent false-PASS):
78
+ * - **Failed read:** `ok === false` (auth revoked / not_in_channel) throws — never a
79
+ * vacuous PASS over a read that returned nothing because it FAILED.
80
+ * - **Truncation guard:** a `next_cursor` (more pages exist) or a full page
81
+ * (>= HISTORY_LIMIT) means the read may be incomplete → AbsenceUnverifiableError →
82
+ * harness BLOCKED, never a false PASS over an unread page.
83
+ * - **Anti-laundering:** ALL text VERSIONS per ts are kept (an edit can't launder a
84
+ * nudge out). **Identity:** user id OR app bot_id (a background nudge may have only
85
+ * bot_id). **Bounded window:** clamped to MAX_WINDOW_MS.
86
+ */
87
+ collectMessages(channelId: string, opts: {
88
+ windowMs: number;
89
+ afterMessageId?: string;
90
+ }): Promise<Array<Omit<ReplyResult, 'responderMachineId'>>>;
62
91
  /** Find the FIRST agent-authored message strictly after `after` (oldest-first). */
63
92
  private findAgentReply;
64
93
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SlackLiveSender.d.ts","sourceRoot":"","sources":["../../src/core/SlackLiveSender.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEpE,oFAAoF;AACpF,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAC9D,EAAE,CAAC,EAAE,OAAO,CAAC;QACb,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,QAAQ,CAAC,EAAE,KAAK,CAAC;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAClG,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;KACtB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,mBAAmB;IAClC,6FAA6F;IAC7F,GAAG,EAAE,WAAW,CAAC;IACjB,iGAAiG;IACjG,cAAc,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,qBAAa,eAAgB,YAAW,aAAa;IACnD,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAsB;gBAC5B,IAAI,EAAE,mBAAmB;IAErC,OAAO,CAAC,GAAG;YACG,KAAK;IAGnB,OAAO,CAAC,GAAG;IAEL,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAU1D,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,GAAG,IAAI,CAAC;IAelJ,mFAAmF;YACrE,cAAc;CAkB7B"}
1
+ {"version":3,"file":"SlackLiveSender.d.ts","sourceRoot":"","sources":["../../src/core/SlackLiveSender.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAMpE,oFAAoF;AACpF,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAC9D,EAAE,CAAC,EAAE,OAAO,CAAC;QACb,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,QAAQ,CAAC,EAAE,KAAK,CAAC;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAClG,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;KACtB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,mBAAmB;IAClC,6FAA6F;IAC7F,GAAG,EAAE,WAAW,CAAC;IACjB,iGAAiG;IACjG,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,qBAAa,eAAgB,YAAW,aAAa;IACnD,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAsB;gBAC5B,IAAI,EAAE,mBAAmB;IAErC,OAAO,CAAC,GAAG;YACG,KAAK;IAGnB,OAAO,CAAC,GAAG;IAEL,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAU1D,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,GAAG,IAAI,CAAC;IAelJ,uFAAuF;IACvF,OAAO,CAAC,eAAe;IAMvB;;;;;;;;;;;;;;OAcG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAmCtJ,mFAAmF;YACrE,cAAc;CAkB7B"}
@@ -19,6 +19,10 @@
19
19
  * the RealChannelDriver's injected placement reader; this sender only returns the
20
20
  * reply text + id.
21
21
  */
22
+ import { AbsenceUnverifiableError } from './LiveTestHarness.js';
23
+ /** History page size + the absolute ceiling on an absence-collection window. */
24
+ const HISTORY_LIMIT = 100;
25
+ const MAX_WINDOW_MS = 300_000;
22
26
  export class SlackLiveSender {
23
27
  d;
24
28
  constructor(deps) { this.d = deps; }
@@ -52,12 +56,73 @@ export class SlackLiveSender {
52
56
  this.log(`no agent reply in ${channelId} within ${opts.timeoutMs}ms`);
53
57
  return null;
54
58
  }
59
+ /** A message is agent-outbound if it is from the agent's user id OR its app bot_id. */
60
+ isAgentAuthored(m) {
61
+ if (m.user === this.d.agentBotUserId)
62
+ return true;
63
+ if (this.d.agentBotId && m.bot_id === this.d.agentBotId)
64
+ return true;
65
+ return false;
66
+ }
67
+ /**
68
+ * Collect EVERY agent-authored message strictly after `after`, polling across the
69
+ * window so a nudge landing LATE (after a legitimate reply) is still seen. Returned
70
+ * oldest-first. Backs the absence assertion over a real Slack channel.
71
+ *
72
+ * Soundness for an ABSENCE proof (an under-collection here is a silent false-PASS):
73
+ * - **Failed read:** `ok === false` (auth revoked / not_in_channel) throws — never a
74
+ * vacuous PASS over a read that returned nothing because it FAILED.
75
+ * - **Truncation guard:** a `next_cursor` (more pages exist) or a full page
76
+ * (>= HISTORY_LIMIT) means the read may be incomplete → AbsenceUnverifiableError →
77
+ * harness BLOCKED, never a false PASS over an unread page.
78
+ * - **Anti-laundering:** ALL text VERSIONS per ts are kept (an edit can't launder a
79
+ * nudge out). **Identity:** user id OR app bot_id (a background nudge may have only
80
+ * bot_id). **Bounded window:** clamped to MAX_WINDOW_MS.
81
+ */
82
+ async collectMessages(channelId, opts) {
83
+ const after = opts.afterMessageId;
84
+ const deadline = this.now() + Math.min(Math.max(0, opts.windowMs), MAX_WINDOW_MS);
85
+ const pollMs = this.d.pollIntervalMs ?? 2000;
86
+ const seen = new Map(); // ts → every text version observed
87
+ for (let first = true; first || this.now() < deadline; first = false) {
88
+ const res = await this.d.api.call('conversations.history', {
89
+ channel: channelId,
90
+ ...(after ? { oldest: after, inclusive: false } : {}),
91
+ limit: HISTORY_LIMIT,
92
+ });
93
+ if (res.ok === false) {
94
+ throw new AbsenceUnverifiableError(`conversations.history failed for ${channelId} (ok=false) — cannot prove absence over a failed read`);
95
+ }
96
+ const messages = res.messages ?? [];
97
+ const nextCursor = res.response_metadata?.next_cursor;
98
+ if ((nextCursor && nextCursor.length > 0) || messages.length >= HISTORY_LIMIT) {
99
+ throw new AbsenceUnverifiableError(`${channelId} history read is paginated/truncated (cursor or full ${HISTORY_LIMIT}-page) — cannot prove completeness`);
100
+ }
101
+ for (const m of messages) {
102
+ if (!m.ts)
103
+ continue; // skip a malformed entry
104
+ if (after && !(m.ts > after))
105
+ continue; // strictly after the prompt
106
+ if (!this.isAgentAuthored(m))
107
+ continue; // agent OUTBOUND only (user id OR bot_id)
108
+ const set = seen.get(m.ts) ?? new Set();
109
+ set.add(m.text ?? '');
110
+ seen.set(m.ts, set);
111
+ }
112
+ if (this.now() >= deadline)
113
+ break;
114
+ await this.sleep(pollMs);
115
+ }
116
+ return [...seen.entries()]
117
+ .sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0))
118
+ .flatMap(([ts, texts]) => [...texts].map(text => ({ messageId: ts, text })));
119
+ }
55
120
  /** Find the FIRST agent-authored message strictly after `after` (oldest-first). */
56
121
  async findAgentReply(channelId, after) {
57
122
  const res = await this.d.api.call('conversations.history', {
58
123
  channel: channelId,
59
124
  ...(after ? { oldest: after, inclusive: false } : {}),
60
- limit: 100,
125
+ limit: HISTORY_LIMIT,
61
126
  });
62
127
  const messages = res.messages ?? [];
63
128
  // conversations.history returns newest-first; scan oldest-first so we return the
@@ -66,8 +131,8 @@ export class SlackLiveSender {
66
131
  for (const m of oldestFirst) {
67
132
  if (after && !(m.ts > after))
68
133
  continue; // strictly-after guard (belt + suspenders vs `oldest`)
69
- if (m.user !== this.d.agentBotUserId)
70
- continue; // only the AGENT's reply
134
+ if (!this.isAgentAuthored(m))
135
+ continue; // only the AGENT's reply (user id OR bot_id)
71
136
  const text = m.text ?? '';
72
137
  return { text, messageId: m.ts };
73
138
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SlackLiveSender.js","sourceRoot":"","sources":["../../src/core/SlackLiveSender.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SlackLiveSender.js","sourceRoot":"","sources":["../../src/core/SlackLiveSender.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAGhE,gFAAgF;AAChF,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,aAAa,GAAG,OAAO,CAAC;AAiC9B,MAAM,OAAO,eAAe;IACT,CAAC,CAAsB;IACxC,YAAY,IAAyB,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IAEjD,GAAG,KAAa,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,KAAK,CAAC,KAAK,CAAC,EAAU;QAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3F,CAAC;IACO,GAAG,CAAC,CAAS,IAAU,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,uBAAuB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAE7E,KAAK,CAAC,IAAI,CAAC,SAAiB,EAAE,IAAY;QACxC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,iFAAiF;YACjF,4CAA4C;YAC5C,MAAM,IAAI,KAAK,CAAC,uCAAuC,GAAG,CAAC,EAAE,wBAAwB,CAAC,CAAC;QACzF,CAAC;QACD,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,SAAiB,EAAE,IAAoD;QACtF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,cAAc,IAAI,IAAI,CAAC;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,wDAAwD;QAC3F,8CAA8C;QAC9C,KAAK,IAAI,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,KAAK,GAAG,KAAK,EAAE,CAAC;YACrE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YAC1D,IAAI,KAAK;gBAAE,OAAO,KAAK,CAAC;YACxB,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ;gBAAE,MAAM;YAClC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,qBAAqB,SAAS,WAAW,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;QACtE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uFAAuF;IAC/E,eAAe,CAAC,CAAqC;QAC3D,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,cAAc;YAAE,OAAO,IAAI,CAAC;QAClD,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QACrE,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,eAAe,CAAC,SAAiB,EAAE,IAAmD;QAC1F,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAC,CAAC;QAClF,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,cAAc,IAAI,IAAI,CAAC;QAC7C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAuB,CAAC,CAAC,mCAAmC;QAChF,KAAK,IAAI,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,KAAK,GAAG,KAAK,EAAE,CAAC;YACrE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE;gBACzD,OAAO,EAAE,SAAS;gBAClB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrD,KAAK,EAAE,aAAa;aACrB,CAAC,CAAC;YACH,IAAI,GAAG,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;gBACrB,MAAM,IAAI,wBAAwB,CAAC,oCAAoC,SAAS,uDAAuD,CAAC,CAAC;YAC3I,CAAC;YACD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC;YACpC,MAAM,UAAU,GAAI,GAAG,CAAC,iBAA0D,EAAE,WAAW,CAAC;YAChG,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,QAAQ,CAAC,MAAM,IAAI,aAAa,EAAE,CAAC;gBAC9E,MAAM,IAAI,wBAAwB,CAAC,GAAG,SAAS,wDAAwD,aAAa,oCAAoC,CAAC,CAAC;YAC5J,CAAC;YACD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACzB,IAAI,CAAC,CAAC,CAAC,EAAE;oBAAE,SAAS,CAAuB,yBAAyB;gBACpE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC;oBAAE,SAAS,CAAI,4BAA4B;gBACvE,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;oBAAE,SAAS,CAAI,0CAA0C;gBACrF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;gBAChD,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;gBACtB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YACtB,CAAC;YACD,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ;gBAAE,MAAM;YAClC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;aACvB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;aACxD,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,mFAAmF;IAC3E,KAAK,CAAC,cAAc,CAAC,SAAiB,EAAE,KAAc;QAC5D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE;YACzD,OAAO,EAAE,SAAS;YAClB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrD,KAAK,EAAE,aAAa;SACrB,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC;QACpC,iFAAiF;QACjF,yDAAyD;QACzD,MAAM,WAAW,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3F,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;YAC5B,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC;gBAAE,SAAS,CAAC,uDAAuD;YAC/F,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;gBAAE,SAAS,CAAC,6CAA6C;YACrF,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;YAC1B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QACnC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
@@ -48,6 +48,24 @@ export declare class TelegramLiveSender implements SurfaceSender {
48
48
  timeoutMs: number;
49
49
  afterMessageId?: string;
50
50
  }): Promise<Omit<ReplyResult, 'responderMachineId'> | null>;
51
+ /**
52
+ * Collect EVERY agent-authored message in the topic strictly after `afterMessageId`,
53
+ * polling across the window so a nudge that lands LATE (after a legitimate reply) is
54
+ * still seen. Returned oldest-first. Backs the absence assertion.
55
+ *
56
+ * Soundness for an ABSENCE proof (an under-collection here is a silent false-PASS):
57
+ * - **Anti-laundering:** ALL distinct text VERSIONS of a messageId are kept (not
58
+ * last-write-wins), so an edit that rewrites a spurious nudge to benign text cannot
59
+ * launder it out of the proof — every observed version is returned and matched.
60
+ * - **Truncation guard:** a poll returning a FULL page (>= HISTORY_LIMIT) means the
61
+ * read may be truncated (a nudge could be on an unread page) → AbsenceUnverifiableError
62
+ * → the harness records BLOCKED, never a false PASS over an incomplete read.
63
+ * - **Bounded window:** windowMs is clamped to MAX_WINDOW_MS (caps real-API poll count).
64
+ */
65
+ collectMessages(channelId: string, opts: {
66
+ windowMs: number;
67
+ afterMessageId?: string;
68
+ }): Promise<Array<Omit<ReplyResult, 'responderMachineId'>>>;
51
69
  private findAgentReply;
52
70
  }
53
71
  //# sourceMappingURL=TelegramLiveSender.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TelegramLiveSender.d.ts","sourceRoot":"","sources":["../../src/core/TelegramLiveSender.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEpE,kFAAkF;AAClF,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,4FAA4F;IAC5F,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC,uGAAuG;IACvG,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClF,4FAA4F;IAC5F,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,oBAAoB,EAAE,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAC1G,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,qBAAa,kBAAmB,YAAW,aAAa;IACtD,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAyB;gBAC/B,IAAI,EAAE,sBAAsB;IAExC,OAAO,CAAC,GAAG;YACG,KAAK;IAGnB,OAAO,CAAC,GAAG;IAEX,OAAO,CAAC,QAAQ;IAMV,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAQ1D,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,GAAG,IAAI,CAAC;YAepI,cAAc;CAW7B"}
1
+ {"version":3,"file":"TelegramLiveSender.d.ts","sourceRoot":"","sources":["../../src/core/TelegramLiveSender.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAMpE,kFAAkF;AAClF,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,4FAA4F;IAC5F,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC,uGAAuG;IACvG,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClF,4FAA4F;IAC5F,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,oBAAoB,EAAE,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAC1G,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,qBAAa,kBAAmB,YAAW,aAAa;IACtD,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAyB;gBAC/B,IAAI,EAAE,sBAAsB;IAExC,OAAO,CAAC,GAAG;YACG,KAAK;IAGnB,OAAO,CAAC,GAAG;IAEX,OAAO,CAAC,QAAQ;IAMV,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAQ1D,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,GAAG,IAAI,CAAC;IAelJ;;;;;;;;;;;;;OAaG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC,CAAC;YAuCxI,cAAc;CAW7B"}
@@ -15,6 +15,10 @@
15
15
  * sent. Null on timeout. The responder-MACHINE attribution (the cross-machine proof) is
16
16
  * the RealChannelDriver's injected placement reader, not this sender.
17
17
  */
18
+ import { AbsenceUnverifiableError } from './LiveTestHarness.js';
19
+ /** History page size + the absolute ceiling on an absence-collection window. */
20
+ const HISTORY_LIMIT = 100;
21
+ const MAX_WINDOW_MS = 300_000;
18
22
  export class TelegramLiveSender {
19
23
  d;
20
24
  constructor(deps) { this.d = deps; }
@@ -52,6 +56,62 @@ export class TelegramLiveSender {
52
56
  this.log(`no agent reply in topic ${topic} within ${opts.timeoutMs}ms`);
53
57
  return null;
54
58
  }
59
+ /**
60
+ * Collect EVERY agent-authored message in the topic strictly after `afterMessageId`,
61
+ * polling across the window so a nudge that lands LATE (after a legitimate reply) is
62
+ * still seen. Returned oldest-first. Backs the absence assertion.
63
+ *
64
+ * Soundness for an ABSENCE proof (an under-collection here is a silent false-PASS):
65
+ * - **Anti-laundering:** ALL distinct text VERSIONS of a messageId are kept (not
66
+ * last-write-wins), so an edit that rewrites a spurious nudge to benign text cannot
67
+ * launder it out of the proof — every observed version is returned and matched.
68
+ * - **Truncation guard:** a poll returning a FULL page (>= HISTORY_LIMIT) means the
69
+ * read may be truncated (a nudge could be on an unread page) → AbsenceUnverifiableError
70
+ * → the harness records BLOCKED, never a false PASS over an incomplete read.
71
+ * - **Bounded window:** windowMs is clamped to MAX_WINDOW_MS (caps real-API poll count).
72
+ */
73
+ async collectMessages(channelId, opts) {
74
+ const topic = this.topicNum(channelId);
75
+ const afterId = opts.afterMessageId != null ? Number(opts.afterMessageId) : -Infinity;
76
+ const deadline = this.now() + Math.min(Math.max(0, opts.windowMs), MAX_WINDOW_MS);
77
+ const pollMs = this.d.pollIntervalMs ?? 2000;
78
+ const seen = new Map(); // messageId → every text version observed
79
+ for (let first = true; first || this.now() < deadline; first = false) {
80
+ const entries = await this.d.getHistory(topic, HISTORY_LIMIT);
81
+ // Telegram getTopicHistory returns the most-recent HISTORY_LIMIT entries of the
82
+ // topic's WHOLE lifetime (a tail, NOT bounded to the marker like Slack's `oldest`).
83
+ // So a full page only means the read is TRUNCATED when its OLDEST entry is still
84
+ // AFTER the marker — i.e. the marker scrolled off the page, so post-marker messages
85
+ // between the marker and the page's oldest may be unread. If the oldest in-page
86
+ // entry is <= the marker, the marker (or older) is in-page → every post-marker
87
+ // message is present → complete, even on a long-lived demo topic with >100 lifetime
88
+ // messages. (Round-2 review: a bare `length >= LIMIT` wrongly blocked any reused topic.)
89
+ if (entries.length >= HISTORY_LIMIT) {
90
+ const ids = entries.map(e => e.messageId).filter(n => Number.isFinite(n));
91
+ const oldestInPage = ids.length ? Math.min(...ids) : -Infinity;
92
+ if (oldestInPage > afterId) {
93
+ throw new AbsenceUnverifiableError(`topic ${topic} full ${HISTORY_LIMIT}-entry page is entirely after the marker — the marker scrolled off, post-marker messages may be unread (cannot prove completeness)`);
94
+ }
95
+ }
96
+ for (const e of entries) {
97
+ if (!Number.isFinite(e.messageId))
98
+ continue; // skip a malformed entry, never a junk key
99
+ if (e.messageId <= afterId)
100
+ continue; // strictly after the prompt we sent
101
+ if (e.fromUser)
102
+ continue; // agent OUTBOUND only (the background-nudge class)
103
+ const set = seen.get(e.messageId) ?? new Set();
104
+ set.add(e.text ?? '');
105
+ seen.set(e.messageId, set);
106
+ }
107
+ if (this.now() >= deadline)
108
+ break;
109
+ await this.sleep(pollMs);
110
+ }
111
+ return [...seen.entries()]
112
+ .sort((a, b) => a[0] - b[0])
113
+ .flatMap(([messageId, texts]) => [...texts].map(text => ({ messageId: String(messageId), text })));
114
+ }
55
115
  async findAgentReply(topicId, afterId) {
56
116
  const entries = await this.d.getHistory(topicId, 100);
57
117
  // Oldest-first by messageId so we return the EARLIEST agent reply after the prompt.
@@ -1 +1 @@
1
- {"version":3,"file":"TelegramLiveSender.js","sourceRoot":"","sources":["../../src/core/TelegramLiveSender.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAwBH,MAAM,OAAO,kBAAkB;IACZ,CAAC,CAAyB;IAC3C,YAAY,IAA4B,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IAEpD,GAAG,KAAa,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,KAAK,CAAC,KAAK,CAAC,EAAU;QAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3F,CAAC;IACO,GAAG,CAAC,CAAS,IAAU,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,0BAA0B,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAExE,QAAQ,CAAC,SAAiB;QAChC,MAAM,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,SAAS,6BAA6B,CAAC,CAAC;QACxG,OAAO,CAAC,CAAC;IACX,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,SAAiB,EAAE,IAAY;QACxC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC;QACxE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC/E,CAAC;QACD,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,SAAiB,EAAE,IAAoD;QACtF,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QACtF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,cAAc,IAAI,IAAI,CAAC;QAC7C,KAAK,IAAI,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,KAAK,GAAG,KAAK,EAAE,CAAC;YACrE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACxD,IAAI,KAAK;gBAAE,OAAO,KAAK,CAAC;YACxB,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ;gBAAE,MAAM;YAClC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,2BAA2B,KAAK,WAAW,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,OAAe,EAAE,OAAe;QAC3D,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACtD,oFAAoF;QACpF,MAAM,WAAW,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;QAC3E,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;YAC5B,IAAI,CAAC,CAAC,SAAS,IAAI,OAAO;gBAAE,SAAS,CAAG,4BAA4B;YACpE,IAAI,CAAC,CAAC,QAAQ;gBAAE,SAAS,CAAe,uDAAuD;YAC/F,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC;QAChE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
1
+ {"version":3,"file":"TelegramLiveSender.js","sourceRoot":"","sources":["../../src/core/TelegramLiveSender.ts"],"names":[],"mappings":"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"}