import test from 'node:test';import assert from 'node:assert/strict';import { decide, reminderText } from '../worker/src/agent.js';const DAY = 86_400_000;const now = 1_800_000_000_000;const rules = { days: 3, bps: 500, hours: 72 };const inv = (o = {}) => ({ status: 'overdue', number: 4, due_at_ms: String(now - 5 * DAY), discount_bps: 0, discount_until_ms: '0', due_now: '100000000', ...o });test('acts on an invoice overdue past the merchant\'s threshold', () => { assert.deepEqual(decide(inv(), rules, now, 200), { bps: 200, until: now + 72 * 3_600_000 });});test('the on-chain cap beats a looser off-chain rule', () => { assert.equal(decide(inv(), rules, now, 200).bps, 200); assert.equal(decide(inv(), { ...rules, bps: 100 }, now, 200).bps, 100); assert.equal(decide(inv(), rules, now, 0).bps, 0);});test('leaves invoices alone when it should', () => { for (const status of ['open', 'paid', 'cancelled', 'refunded', 'partially_refunded']) { assert.equal(decide(inv({ status }), rules, now, 200), null, status); } assert.equal(decide(inv({ due_at_ms: String(now - 2 * DAY) }), rules, now, 200), null);});test('does not stack a second offer on a live one', () => { assert.equal(decide(inv({ discount_bps: 200, discount_until_ms: String(now + DAY) }), rules, now, 200), null); assert.ok(decide(inv({ discount_bps: 200, discount_until_ms: String(now - DAY) }), rules, now, 200));});test('a reminder states the amount and only mentions an offer that was made', () => { const made = reminderText(inv(), { bps: 200, until: now }, 'https://x/i/1-4'); assert.match(made, /\$100\.00/); assert.match(made, /2% off/); assert.doesNotMatch(reminderText(inv(), { bps: 0, until: now }, 'https://x/i/1-4'), /off if/);});test('every sponsored or agent call carries the gas the contract demands for a payout', async () => { const { readFileSync } = await import('node:fs'); const { SWEEP_TGAS } = await import('../worker/src/agent.js'); const { METHODS } = await import('../worker/src/policy.js'); const src = readFileSync(new URL('../contract/src/lib.rs', import.meta.url), 'utf8'); const tgas = (name) => BigInt(src.match(new RegExp(`const ${name}: Gas = Gas::from_tgas\\((\\d+)\\)`))[1]); const overhead = tgas('GAS_CALLBACK') + tgas('GAS_OVERHEAD'); assert.ok(SWEEP_TGAS >= tgas('GAS_FT_TRANSFER') + overhead, 'agent_sweep'); const needed = (tgas('GAS_FT_TRANSFER_CALL') + overhead) * 1_000_000_000_000n; assert.ok(METHODS.withdraw.gas >= needed, 'withdraw through Intents'); assert.ok(METHODS.refund.gas >= needed, 'refund through Intents');});