@principles/core 1.73.0 → 1.75.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.
- package/dist/runtime-v2/__tests__/architecture-regression.test.js +3 -3
- package/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/dist/runtime-v2/activation/index.d.ts +0 -2
- package/dist/runtime-v2/activation/index.d.ts.map +1 -1
- package/dist/runtime-v2/activation/index.js +0 -1
- package/dist/runtime-v2/activation/index.js.map +1 -1
- package/dist/runtime-v2/adapter/__tests__/schema-prompt-adapter.test.d.ts +2 -0
- package/dist/runtime-v2/adapter/__tests__/schema-prompt-adapter.test.d.ts.map +1 -0
- package/dist/runtime-v2/adapter/__tests__/schema-prompt-adapter.test.js +270 -0
- package/dist/runtime-v2/adapter/__tests__/schema-prompt-adapter.test.js.map +1 -0
- package/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts +1 -1
- package/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts.map +1 -1
- package/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js +4 -3
- package/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js.map +1 -1
- package/dist/runtime-v2/adapter/schema-prompt-adapter.d.ts +13 -0
- package/dist/runtime-v2/adapter/schema-prompt-adapter.d.ts.map +1 -0
- package/dist/runtime-v2/adapter/schema-prompt-adapter.js +266 -0
- package/dist/runtime-v2/adapter/schema-prompt-adapter.js.map +1 -0
- package/dist/runtime-v2/adapter/tools/diagnostician-tool.d.ts +3 -7
- package/dist/runtime-v2/adapter/tools/diagnostician-tool.d.ts.map +1 -1
- package/dist/runtime-v2/adapter/tools/diagnostician-tool.js +7 -19
- package/dist/runtime-v2/adapter/tools/diagnostician-tool.js.map +1 -1
- package/dist/runtime-v2/diagnostician/__tests__/diagnostician-prompt-builder.test.js +97 -15
- package/dist/runtime-v2/diagnostician/__tests__/diagnostician-prompt-builder.test.js.map +1 -1
- package/dist/runtime-v2/diagnostician-output.d.ts +0 -10
- package/dist/runtime-v2/diagnostician-output.d.ts.map +1 -1
- package/dist/runtime-v2/diagnostician-output.js +5 -10
- package/dist/runtime-v2/diagnostician-output.js.map +1 -1
- package/dist/runtime-v2/diagnostician-prompt-builder.d.ts +6 -1
- package/dist/runtime-v2/diagnostician-prompt-builder.d.ts.map +1 -1
- package/dist/runtime-v2/diagnostician-prompt-builder.js +23 -15
- package/dist/runtime-v2/diagnostician-prompt-builder.js.map +1 -1
- package/dist/runtime-v2/index.d.ts +4 -4
- package/dist/runtime-v2/index.d.ts.map +1 -1
- package/dist/runtime-v2/index.js +2 -2
- package/dist/runtime-v2/index.js.map +1 -1
- package/dist/runtime-v2/types/event-types.d.ts +3 -24
- package/dist/runtime-v2/types/event-types.d.ts.map +1 -1
- package/dist/runtime-v2/types/event-types.js +0 -10
- package/dist/runtime-v2/types/event-types.js.map +1 -1
- package/package.json +1 -1
- package/dist/runtime-v2/__tests__/nocturnal-compliance-trust-boundary.test.d.ts +0 -2
- package/dist/runtime-v2/__tests__/nocturnal-compliance-trust-boundary.test.d.ts.map +0 -1
- package/dist/runtime-v2/__tests__/nocturnal-compliance-trust-boundary.test.js +0 -215
- package/dist/runtime-v2/__tests__/nocturnal-compliance-trust-boundary.test.js.map +0 -1
- package/dist/runtime-v2/__tests__/sqlite-confirm-first-state-store.test.d.ts +0 -2
- package/dist/runtime-v2/__tests__/sqlite-confirm-first-state-store.test.d.ts.map +0 -1
- package/dist/runtime-v2/__tests__/sqlite-confirm-first-state-store.test.js +0 -148
- package/dist/runtime-v2/__tests__/sqlite-confirm-first-state-store.test.js.map +0 -1
- package/dist/runtime-v2/activation/sqlite-confirm-first-state-store.d.ts +0 -22
- package/dist/runtime-v2/activation/sqlite-confirm-first-state-store.d.ts.map +0 -1
- package/dist/runtime-v2/activation/sqlite-confirm-first-state-store.js +0 -136
- package/dist/runtime-v2/activation/sqlite-confirm-first-state-store.js.map +0 -1
- package/dist/runtime-v2/idle-trigger/__tests__/idle-trigger-config-resolve.test.d.ts +0 -2
- package/dist/runtime-v2/idle-trigger/__tests__/idle-trigger-config-resolve.test.d.ts.map +0 -1
- package/dist/runtime-v2/idle-trigger/__tests__/idle-trigger-config-resolve.test.js +0 -92
- package/dist/runtime-v2/idle-trigger/__tests__/idle-trigger-config-resolve.test.js.map +0 -1
- package/dist/runtime-v2/idle-trigger/__tests__/idle-trigger-decision.test.d.ts +0 -2
- package/dist/runtime-v2/idle-trigger/__tests__/idle-trigger-decision.test.d.ts.map +0 -1
- package/dist/runtime-v2/idle-trigger/__tests__/idle-trigger-decision.test.js +0 -134
- package/dist/runtime-v2/idle-trigger/__tests__/idle-trigger-decision.test.js.map +0 -1
- package/dist/runtime-v2/idle-trigger/__tests__/idle-trigger-edge-cases.test.d.ts +0 -2
- package/dist/runtime-v2/idle-trigger/__tests__/idle-trigger-edge-cases.test.d.ts.map +0 -1
- package/dist/runtime-v2/idle-trigger/__tests__/idle-trigger-edge-cases.test.js +0 -226
- package/dist/runtime-v2/idle-trigger/__tests__/idle-trigger-edge-cases.test.js.map +0 -1
- package/dist/runtime-v2/idle-trigger/idle-trigger-decision.d.ts +0 -3
- package/dist/runtime-v2/idle-trigger/idle-trigger-decision.d.ts.map +0 -1
- package/dist/runtime-v2/idle-trigger/idle-trigger-decision.js +0 -5
- package/dist/runtime-v2/idle-trigger/idle-trigger-decision.js.map +0 -1
- package/dist/runtime-v2/idle-trigger/idle-trigger-policy.d.ts +0 -4
- package/dist/runtime-v2/idle-trigger/idle-trigger-policy.d.ts.map +0 -1
- package/dist/runtime-v2/idle-trigger/idle-trigger-policy.js +0 -81
- package/dist/runtime-v2/idle-trigger/idle-trigger-policy.js.map +0 -1
- package/dist/runtime-v2/idle-trigger/idle-trigger-types.d.ts +0 -29
- package/dist/runtime-v2/idle-trigger/idle-trigger-types.d.ts.map +0 -1
- package/dist/runtime-v2/idle-trigger/idle-trigger-types.js +0 -15
- package/dist/runtime-v2/idle-trigger/idle-trigger-types.js.map +0 -1
- package/dist/runtime-v2/idle-trigger/index.d.ts +0 -5
- package/dist/runtime-v2/idle-trigger/index.d.ts.map +0 -1
- package/dist/runtime-v2/idle-trigger/index.js +0 -4
- package/dist/runtime-v2/idle-trigger/index.js.map +0 -1
- package/dist/runtime-v2/nocturnal/candidate-scoring.d.ts +0 -486
- package/dist/runtime-v2/nocturnal/candidate-scoring.d.ts.map +0 -1
- package/dist/runtime-v2/nocturnal/candidate-scoring.js +0 -493
- package/dist/runtime-v2/nocturnal/candidate-scoring.js.map +0 -1
- package/dist/runtime-v2/nocturnal/index.d.ts +0 -9
- package/dist/runtime-v2/nocturnal/index.d.ts.map +0 -1
- package/dist/runtime-v2/nocturnal/index.js +0 -5
- package/dist/runtime-v2/nocturnal/index.js.map +0 -1
- package/dist/runtime-v2/nocturnal/nocturnal-compliance.d.ts +0 -185
- package/dist/runtime-v2/nocturnal/nocturnal-compliance.d.ts.map +0 -1
- package/dist/runtime-v2/nocturnal/nocturnal-compliance.js +0 -912
- package/dist/runtime-v2/nocturnal/nocturnal-compliance.js.map +0 -1
- package/dist/runtime-v2/nocturnal/snapshot-contract.d.ts +0 -192
- package/dist/runtime-v2/nocturnal/snapshot-contract.d.ts.map +0 -1
- package/dist/runtime-v2/nocturnal/snapshot-contract.js +0 -185
- package/dist/runtime-v2/nocturnal/snapshot-contract.js.map +0 -1
- package/dist/runtime-v2/nocturnal/trinity-types.d.ts +0 -421
- package/dist/runtime-v2/nocturnal/trinity-types.d.ts.map +0 -1
- package/dist/runtime-v2/nocturnal/trinity-types.js +0 -182
- package/dist/runtime-v2/nocturnal/trinity-types.js.map +0 -1
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
const MAX_SESSION_ENTRIES = 500;
|
|
2
|
-
const STALE_ROW_DAYS = 30;
|
|
3
|
-
function isRecord(value) {
|
|
4
|
-
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
5
|
-
}
|
|
6
|
-
function readStringField(row, key) {
|
|
7
|
-
if (!Object.hasOwn(row, key))
|
|
8
|
-
return null;
|
|
9
|
-
const val = row[key];
|
|
10
|
-
return typeof val === 'string' && val.length > 0 ? val : null;
|
|
11
|
-
}
|
|
12
|
-
function mapRowToRecord(row) {
|
|
13
|
-
if (!isRecord(row))
|
|
14
|
-
return null;
|
|
15
|
-
const sessionId = readStringField(row, 'session_id');
|
|
16
|
-
const directiveSetAt = readStringField(row, 'directive_set_at');
|
|
17
|
-
const lastSeenAt = readStringField(row, 'last_seen_at');
|
|
18
|
-
if (!sessionId || !directiveSetAt || !lastSeenAt)
|
|
19
|
-
return null;
|
|
20
|
-
const directiveActive = row.directive_active === 1;
|
|
21
|
-
const directivePrincipleId = readStringField(row, 'directive_principle_id');
|
|
22
|
-
const approvalActive = row.approval_active === 1;
|
|
23
|
-
const approvalSetAt = readStringField(row, 'approval_set_at');
|
|
24
|
-
return {
|
|
25
|
-
sessionId,
|
|
26
|
-
directiveActive,
|
|
27
|
-
directivePrincipleId,
|
|
28
|
-
directiveSetAt,
|
|
29
|
-
approvalActive,
|
|
30
|
-
approvalSetAt,
|
|
31
|
-
lastSeenAt,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
export class SqliteConfirmFirstStateStore {
|
|
35
|
-
connection;
|
|
36
|
-
constructor(connection) {
|
|
37
|
-
this.connection = connection;
|
|
38
|
-
}
|
|
39
|
-
upsertDirective(sessionId, active, principleId) {
|
|
40
|
-
const db = this.connection.getDb();
|
|
41
|
-
const now = new Date().toISOString();
|
|
42
|
-
db.prepare(`
|
|
43
|
-
INSERT INTO confirm_first_state (session_id, directive_active, directive_principle_id, directive_set_at, last_seen_at)
|
|
44
|
-
VALUES (?, ?, ?, ?, ?)
|
|
45
|
-
ON CONFLICT(session_id) DO UPDATE SET
|
|
46
|
-
directive_active=excluded.directive_active,
|
|
47
|
-
directive_principle_id=excluded.directive_principle_id,
|
|
48
|
-
directive_set_at=excluded.directive_set_at,
|
|
49
|
-
last_seen_at=excluded.last_seen_at
|
|
50
|
-
`).run(sessionId, active ? 1 : 0, principleId ?? null, now, now);
|
|
51
|
-
}
|
|
52
|
-
upsertApproval(sessionId) {
|
|
53
|
-
const db = this.connection.getDb();
|
|
54
|
-
const now = new Date().toISOString();
|
|
55
|
-
db.prepare(`
|
|
56
|
-
INSERT INTO confirm_first_state (session_id, approval_active, approval_set_at, last_seen_at, directive_active, directive_set_at)
|
|
57
|
-
VALUES (?, 1, ?, ?, 0, '')
|
|
58
|
-
ON CONFLICT(session_id) DO UPDATE SET
|
|
59
|
-
approval_active=1,
|
|
60
|
-
approval_set_at=excluded.approval_set_at,
|
|
61
|
-
last_seen_at=excluded.last_seen_at
|
|
62
|
-
`).run(sessionId, now, now);
|
|
63
|
-
}
|
|
64
|
-
getState(sessionId) {
|
|
65
|
-
try {
|
|
66
|
-
const db = this.connection.getDb();
|
|
67
|
-
const row = db.prepare(`
|
|
68
|
-
SELECT session_id, directive_active, directive_principle_id, directive_set_at,
|
|
69
|
-
approval_active, approval_set_at, last_seen_at
|
|
70
|
-
FROM confirm_first_state
|
|
71
|
-
WHERE session_id = ?
|
|
72
|
-
`).get(sessionId);
|
|
73
|
-
return mapRowToRecord(row);
|
|
74
|
-
}
|
|
75
|
-
catch (err) {
|
|
76
|
-
if (err instanceof Error && err.message.includes('no such table'))
|
|
77
|
-
return null;
|
|
78
|
-
throw err;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
deleteState(sessionId) {
|
|
82
|
-
const db = this.connection.getDb();
|
|
83
|
-
db.prepare('DELETE FROM confirm_first_state WHERE session_id = ?').run(sessionId);
|
|
84
|
-
}
|
|
85
|
-
deleteAllState() {
|
|
86
|
-
const db = this.connection.getDb();
|
|
87
|
-
db.prepare('DELETE FROM confirm_first_state').run();
|
|
88
|
-
}
|
|
89
|
-
pruneStaleRows() {
|
|
90
|
-
const db = this.connection.getDb();
|
|
91
|
-
const staleResult = db.prepare(`DELETE FROM confirm_first_state WHERE datetime(last_seen_at) < datetime('now', '-${STALE_ROW_DAYS} days')`).run();
|
|
92
|
-
let pruned = staleResult.changes;
|
|
93
|
-
const countRow = db.prepare('SELECT COUNT(*) as cnt FROM confirm_first_state').get();
|
|
94
|
-
if (isRecord(countRow) && Object.hasOwn(countRow, 'cnt')) {
|
|
95
|
-
const total = Number(countRow.cnt);
|
|
96
|
-
if (total > MAX_SESSION_ENTRIES) {
|
|
97
|
-
const excess = total - MAX_SESSION_ENTRIES;
|
|
98
|
-
const excessResult = db.prepare(`
|
|
99
|
-
DELETE FROM confirm_first_state
|
|
100
|
-
WHERE session_id IN (
|
|
101
|
-
SELECT session_id FROM confirm_first_state
|
|
102
|
-
ORDER BY last_seen_at ASC
|
|
103
|
-
LIMIT ?
|
|
104
|
-
)
|
|
105
|
-
`).run(excess);
|
|
106
|
-
pruned += excessResult.changes;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return pruned;
|
|
110
|
-
}
|
|
111
|
-
getAllState() {
|
|
112
|
-
try {
|
|
113
|
-
const db = this.connection.getDb();
|
|
114
|
-
const rows = db.prepare(`
|
|
115
|
-
SELECT session_id, directive_active, directive_principle_id, directive_set_at,
|
|
116
|
-
approval_active, approval_set_at, last_seen_at
|
|
117
|
-
FROM confirm_first_state
|
|
118
|
-
`).all();
|
|
119
|
-
if (!Array.isArray(rows))
|
|
120
|
-
return [];
|
|
121
|
-
const result = [];
|
|
122
|
-
for (const row of rows) {
|
|
123
|
-
const record = mapRowToRecord(row);
|
|
124
|
-
if (record)
|
|
125
|
-
result.push(record);
|
|
126
|
-
}
|
|
127
|
-
return result;
|
|
128
|
-
}
|
|
129
|
-
catch (err) {
|
|
130
|
-
if (err instanceof Error && err.message.includes('no such table'))
|
|
131
|
-
return [];
|
|
132
|
-
throw err;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
//# sourceMappingURL=sqlite-confirm-first-state-store.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-confirm-first-state-store.js","sourceRoot":"","sources":["../../../src/runtime-v2/activation/sqlite-confirm-first-state-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"idle-trigger-config-resolve.test.d.ts","sourceRoot":"","sources":["../../../../src/runtime-v2/idle-trigger/__tests__/idle-trigger-config-resolve.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { resolveIdleTriggerConfig, DEFAULT_IDLE_TRIGGER_CONFIG } from '../index.js';
|
|
3
|
-
describe('resolveIdleTriggerConfig', () => {
|
|
4
|
-
it('undefined partial returns full default config', () => {
|
|
5
|
-
const result = resolveIdleTriggerConfig(undefined);
|
|
6
|
-
expect(result).toEqual(DEFAULT_IDLE_TRIGGER_CONFIG);
|
|
7
|
-
});
|
|
8
|
-
it('empty object partial returns full default config', () => {
|
|
9
|
-
const result = resolveIdleTriggerConfig({});
|
|
10
|
-
expect(result).toEqual(DEFAULT_IDLE_TRIGGER_CONFIG);
|
|
11
|
-
});
|
|
12
|
-
it('partial enabled=false overrides only enabled', () => {
|
|
13
|
-
const result = resolveIdleTriggerConfig({ enabled: false });
|
|
14
|
-
expect(result.enabled).toBe(false);
|
|
15
|
-
expect(result.idleThresholdMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.idleThresholdMs);
|
|
16
|
-
expect(result.jitterMaxMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.jitterMaxMs);
|
|
17
|
-
expect(result.activityCooldownMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.activityCooldownMs);
|
|
18
|
-
});
|
|
19
|
-
it('partial enabled=true overrides only enabled', () => {
|
|
20
|
-
const result = resolveIdleTriggerConfig({ enabled: true });
|
|
21
|
-
expect(result.enabled).toBe(true);
|
|
22
|
-
expect(result.idleThresholdMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.idleThresholdMs);
|
|
23
|
-
});
|
|
24
|
-
it('partial idleThresholdMs overrides only idleThresholdMs', () => {
|
|
25
|
-
const result = resolveIdleTriggerConfig({ idleThresholdMs: 600000 });
|
|
26
|
-
expect(result.idleThresholdMs).toBe(600000);
|
|
27
|
-
expect(result.enabled).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.enabled);
|
|
28
|
-
expect(result.jitterMaxMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.jitterMaxMs);
|
|
29
|
-
expect(result.activityCooldownMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.activityCooldownMs);
|
|
30
|
-
});
|
|
31
|
-
it('partial jitterMaxMs overrides only jitterMaxMs', () => {
|
|
32
|
-
const result = resolveIdleTriggerConfig({ jitterMaxMs: 60000 });
|
|
33
|
-
expect(result.jitterMaxMs).toBe(60000);
|
|
34
|
-
expect(result.enabled).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.enabled);
|
|
35
|
-
expect(result.idleThresholdMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.idleThresholdMs);
|
|
36
|
-
expect(result.activityCooldownMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.activityCooldownMs);
|
|
37
|
-
});
|
|
38
|
-
it('partial activityCooldownMs overrides only activityCooldownMs', () => {
|
|
39
|
-
const result = resolveIdleTriggerConfig({ activityCooldownMs: 120000 });
|
|
40
|
-
expect(result.activityCooldownMs).toBe(120000);
|
|
41
|
-
expect(result.enabled).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.enabled);
|
|
42
|
-
expect(result.idleThresholdMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.idleThresholdMs);
|
|
43
|
-
expect(result.jitterMaxMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.jitterMaxMs);
|
|
44
|
-
});
|
|
45
|
-
it('all fields partial overrides all fields', () => {
|
|
46
|
-
const overrides = {
|
|
47
|
-
enabled: false,
|
|
48
|
-
idleThresholdMs: 900000,
|
|
49
|
-
jitterMaxMs: 45000,
|
|
50
|
-
activityCooldownMs: 180000,
|
|
51
|
-
};
|
|
52
|
-
const result = resolveIdleTriggerConfig(overrides);
|
|
53
|
-
expect(result).toEqual(overrides);
|
|
54
|
-
});
|
|
55
|
-
it('single field partial preserves defaults for other fields', () => {
|
|
56
|
-
const result = resolveIdleTriggerConfig({ idleThresholdMs: 120000 });
|
|
57
|
-
expect(result.idleThresholdMs).toBe(120000);
|
|
58
|
-
expect(result.enabled).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.enabled);
|
|
59
|
-
expect(result.jitterMaxMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.jitterMaxMs);
|
|
60
|
-
expect(result.activityCooldownMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.activityCooldownMs);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
describe('DEFAULT_IDLE_TRIGGER_CONFIG', () => {
|
|
64
|
-
it('has required fields', () => {
|
|
65
|
-
expect(DEFAULT_IDLE_TRIGGER_CONFIG).toHaveProperty('enabled');
|
|
66
|
-
expect(DEFAULT_IDLE_TRIGGER_CONFIG).toHaveProperty('idleThresholdMs');
|
|
67
|
-
expect(DEFAULT_IDLE_TRIGGER_CONFIG).toHaveProperty('jitterMaxMs');
|
|
68
|
-
expect(DEFAULT_IDLE_TRIGGER_CONFIG).toHaveProperty('activityCooldownMs');
|
|
69
|
-
});
|
|
70
|
-
it('enabled defaults to true', () => {
|
|
71
|
-
expect(DEFAULT_IDLE_TRIGGER_CONFIG.enabled).toBe(true);
|
|
72
|
-
});
|
|
73
|
-
it('idleThresholdMs is positive number', () => {
|
|
74
|
-
expect(typeof DEFAULT_IDLE_TRIGGER_CONFIG.idleThresholdMs).toBe('number');
|
|
75
|
-
expect(DEFAULT_IDLE_TRIGGER_CONFIG.idleThresholdMs).toBeGreaterThan(0);
|
|
76
|
-
});
|
|
77
|
-
it('jitterMaxMs is non-negative number', () => {
|
|
78
|
-
expect(typeof DEFAULT_IDLE_TRIGGER_CONFIG.jitterMaxMs).toBe('number');
|
|
79
|
-
expect(DEFAULT_IDLE_TRIGGER_CONFIG.jitterMaxMs).toBeGreaterThanOrEqual(0);
|
|
80
|
-
});
|
|
81
|
-
it('activityCooldownMs is positive number', () => {
|
|
82
|
-
expect(typeof DEFAULT_IDLE_TRIGGER_CONFIG.activityCooldownMs).toBe('number');
|
|
83
|
-
expect(DEFAULT_IDLE_TRIGGER_CONFIG.activityCooldownMs).toBeGreaterThan(0);
|
|
84
|
-
});
|
|
85
|
-
it('jitterMaxMs is less than or equal to idleThresholdMs', () => {
|
|
86
|
-
expect(DEFAULT_IDLE_TRIGGER_CONFIG.jitterMaxMs).toBeLessThanOrEqual(DEFAULT_IDLE_TRIGGER_CONFIG.idleThresholdMs);
|
|
87
|
-
});
|
|
88
|
-
it('activityCooldownMs is less than idleThresholdMs', () => {
|
|
89
|
-
expect(DEFAULT_IDLE_TRIGGER_CONFIG.activityCooldownMs).toBeLessThan(DEFAULT_IDLE_TRIGGER_CONFIG.idleThresholdMs);
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
//# sourceMappingURL=idle-trigger-config-resolve.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"idle-trigger-config-resolve.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/idle-trigger/__tests__/idle-trigger-config-resolve.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"idle-trigger-decision.test.d.ts","sourceRoot":"","sources":["../../../../src/runtime-v2/idle-trigger/__tests__/idle-trigger-decision.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { evaluateIdleTriggerDecision, evaluateIdleTrigger, computeJitterMs, DEFAULT_IDLE_TRIGGER_CONFIG, resolveIdleTriggerConfig, } from '../index.js';
|
|
3
|
-
const NOW = '2026-05-17T12:00:00.000Z';
|
|
4
|
-
const NOW_MS = new Date(NOW).getTime();
|
|
5
|
-
function makeInput(overrides) {
|
|
6
|
-
return {
|
|
7
|
-
lastActivityAt: new Date(NOW_MS - 600_000).toISOString(),
|
|
8
|
-
queue: { readyCount: 1, pendingCount: 1, retryWaitCount: 0 },
|
|
9
|
-
config: DEFAULT_IDLE_TRIGGER_CONFIG,
|
|
10
|
-
jitterSeed: 'test-seed',
|
|
11
|
-
now: NOW,
|
|
12
|
-
...overrides,
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
describe('IdleTrigger Decision Model (PRI-143)', () => {
|
|
16
|
-
it('idle duration exceeds threshold with ready tasks → trigger', () => {
|
|
17
|
-
const input = makeInput({
|
|
18
|
-
lastActivityAt: new Date(NOW_MS - 600_000).toISOString(),
|
|
19
|
-
queue: { readyCount: 1, pendingCount: 1, retryWaitCount: 0 },
|
|
20
|
-
});
|
|
21
|
-
const result = evaluateIdleTriggerDecision(input);
|
|
22
|
-
expect(result.decision).toBe('trigger');
|
|
23
|
-
expect(result.reason).toBe('idle_threshold_met');
|
|
24
|
-
expect(result.idleForMs).toBe(600_000);
|
|
25
|
-
expect(result.queue.readyCount).toBe(1);
|
|
26
|
-
});
|
|
27
|
-
it('idle duration below threshold → skip with reason=not_idle_enough', () => {
|
|
28
|
-
const input = makeInput({
|
|
29
|
-
lastActivityAt: new Date(NOW_MS - 100_000).toISOString(),
|
|
30
|
-
queue: { readyCount: 1, pendingCount: 1, retryWaitCount: 0 },
|
|
31
|
-
});
|
|
32
|
-
const result = evaluateIdleTriggerDecision(input);
|
|
33
|
-
expect(result.decision).toBe('skip');
|
|
34
|
-
expect(result.reason).toBe('not_idle_enough');
|
|
35
|
-
expect(result.idleForMs).toBe(100_000);
|
|
36
|
-
});
|
|
37
|
-
it('no ready tasks → skip with reason=no_ready_tasks', () => {
|
|
38
|
-
const input = makeInput({
|
|
39
|
-
lastActivityAt: new Date(NOW_MS - 600_000).toISOString(),
|
|
40
|
-
queue: { readyCount: 0, pendingCount: 0, retryWaitCount: 0 },
|
|
41
|
-
});
|
|
42
|
-
const result = evaluateIdleTriggerDecision(input);
|
|
43
|
-
expect(result.decision).toBe('skip');
|
|
44
|
-
expect(result.reason).toBe('no_ready_tasks');
|
|
45
|
-
});
|
|
46
|
-
it('jitter is deterministic with same seed', () => {
|
|
47
|
-
const seed = 'deterministic-seed-123';
|
|
48
|
-
const j1 = computeJitterMs(seed, 30_000);
|
|
49
|
-
const j2 = computeJitterMs(seed, 30_000);
|
|
50
|
-
const j3 = computeJitterMs(seed, 30_000);
|
|
51
|
-
expect(j1).toBe(j2);
|
|
52
|
-
expect(j2).toBe(j3);
|
|
53
|
-
expect(j1).toBeGreaterThanOrEqual(0);
|
|
54
|
-
expect(j1).toBeLessThanOrEqual(30_000);
|
|
55
|
-
});
|
|
56
|
-
it('jitter produces different values for different seeds', () => {
|
|
57
|
-
const j1 = computeJitterMs('seed-a', 30_000);
|
|
58
|
-
const j2 = computeJitterMs('seed-b', 30_000);
|
|
59
|
-
expect(typeof j1).toBe('number');
|
|
60
|
-
expect(typeof j2).toBe('number');
|
|
61
|
-
});
|
|
62
|
-
it('config missing fields → safe defaults via resolveIdleTriggerConfig', () => {
|
|
63
|
-
const resolved = resolveIdleTriggerConfig({ enabled: true });
|
|
64
|
-
expect(resolved.idleThresholdMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.idleThresholdMs);
|
|
65
|
-
expect(resolved.jitterMaxMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.jitterMaxMs);
|
|
66
|
-
expect(resolved.activityCooldownMs).toBe(DEFAULT_IDLE_TRIGGER_CONFIG.activityCooldownMs);
|
|
67
|
-
expect(resolved.enabled).toBe(true);
|
|
68
|
-
const emptyResolved = resolveIdleTriggerConfig();
|
|
69
|
-
expect(emptyResolved).toEqual(DEFAULT_IDLE_TRIGGER_CONFIG);
|
|
70
|
-
});
|
|
71
|
-
it('disabled config → skip with reason=disabled', () => {
|
|
72
|
-
const config = { ...DEFAULT_IDLE_TRIGGER_CONFIG, enabled: false };
|
|
73
|
-
const input = makeInput({
|
|
74
|
-
config,
|
|
75
|
-
lastActivityAt: new Date(NOW_MS - 600_000).toISOString(),
|
|
76
|
-
queue: { readyCount: 1, pendingCount: 1, retryWaitCount: 0 },
|
|
77
|
-
});
|
|
78
|
-
const result = evaluateIdleTriggerDecision(input);
|
|
79
|
-
expect(result.decision).toBe('skip');
|
|
80
|
-
expect(result.reason).toBe('disabled');
|
|
81
|
-
});
|
|
82
|
-
it('retry_wait pending with no ready tasks → skip with reason=retry_wait_pending', () => {
|
|
83
|
-
const input = makeInput({
|
|
84
|
-
lastActivityAt: new Date(NOW_MS - 600_000).toISOString(),
|
|
85
|
-
queue: { readyCount: 0, pendingCount: 2, retryWaitCount: 3 },
|
|
86
|
-
});
|
|
87
|
-
const result = evaluateIdleTriggerDecision(input);
|
|
88
|
-
expect(result.decision).toBe('skip');
|
|
89
|
-
expect(result.reason).toBe('retry_wait_pending');
|
|
90
|
-
});
|
|
91
|
-
it('lastActivityAt within activityCooldownMs → skip with reason=not_idle_enough', () => {
|
|
92
|
-
const config = {
|
|
93
|
-
...DEFAULT_IDLE_TRIGGER_CONFIG,
|
|
94
|
-
idleThresholdMs: 10_000,
|
|
95
|
-
activityCooldownMs: 120_000,
|
|
96
|
-
};
|
|
97
|
-
const input = makeInput({
|
|
98
|
-
config,
|
|
99
|
-
lastActivityAt: new Date(NOW_MS - 60_000).toISOString(),
|
|
100
|
-
queue: { readyCount: 1, pendingCount: 1, retryWaitCount: 0 },
|
|
101
|
-
});
|
|
102
|
-
const result = evaluateIdleTriggerDecision(input);
|
|
103
|
-
expect(result.decision).toBe('skip');
|
|
104
|
-
expect(result.reason).toBe('not_idle_enough');
|
|
105
|
-
});
|
|
106
|
-
it('null lastActivityAt treats idle as infinite → trigger when ready tasks exist', () => {
|
|
107
|
-
const input = makeInput({
|
|
108
|
-
lastActivityAt: null,
|
|
109
|
-
queue: { readyCount: 1, pendingCount: 1, retryWaitCount: 0 },
|
|
110
|
-
});
|
|
111
|
-
const result = evaluateIdleTriggerDecision(input);
|
|
112
|
-
expect(result.decision).toBe('trigger');
|
|
113
|
-
expect(result.idleForMs).toBe(NOW_MS);
|
|
114
|
-
});
|
|
115
|
-
it('evaluateIdleTrigger and evaluateIdleTriggerDecision produce identical results', () => {
|
|
116
|
-
const input = makeInput();
|
|
117
|
-
const r1 = evaluateIdleTrigger(input);
|
|
118
|
-
const r2 = evaluateIdleTriggerDecision(input);
|
|
119
|
-
expect(r1).toEqual(r2);
|
|
120
|
-
});
|
|
121
|
-
it('computeJitterMs with maxMs=0 returns 0', () => {
|
|
122
|
-
expect(computeJitterMs('any-seed', 0)).toBe(0);
|
|
123
|
-
});
|
|
124
|
-
it('result includes jitterMs from seeded jitter', () => {
|
|
125
|
-
const input = makeInput({
|
|
126
|
-
lastActivityAt: new Date(NOW_MS - 600_000).toISOString(),
|
|
127
|
-
jitterSeed: 'jitter-test',
|
|
128
|
-
});
|
|
129
|
-
const result = evaluateIdleTriggerDecision(input);
|
|
130
|
-
const expectedJitter = computeJitterMs('jitter-test', DEFAULT_IDLE_TRIGGER_CONFIG.jitterMaxMs);
|
|
131
|
-
expect(result.jitterMs).toBe(expectedJitter);
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
//# sourceMappingURL=idle-trigger-decision.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"idle-trigger-decision.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/idle-trigger/__tests__/idle-trigger-decision.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"idle-trigger-edge-cases.test.d.ts","sourceRoot":"","sources":["../../../../src/runtime-v2/idle-trigger/__tests__/idle-trigger-edge-cases.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { evaluateIdleTrigger, DEFAULT_IDLE_TRIGGER_CONFIG } from '../index.js';
|
|
3
|
-
const NOW = '2026-05-17T12:00:00.000Z';
|
|
4
|
-
const NOW_MS = new Date(NOW).getTime();
|
|
5
|
-
function makeInput(overrides) {
|
|
6
|
-
return {
|
|
7
|
-
lastActivityAt: new Date(NOW_MS - 600_000).toISOString(),
|
|
8
|
-
queue: { readyCount: 1, pendingCount: 1, retryWaitCount: 0 },
|
|
9
|
-
config: { ...DEFAULT_IDLE_TRIGGER_CONFIG },
|
|
10
|
-
jitterSeed: 'test-seed',
|
|
11
|
-
now: NOW,
|
|
12
|
-
...overrides,
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
describe('evaluateIdleTrigger edge cases', () => {
|
|
16
|
-
describe('queue state variations', () => {
|
|
17
|
-
it('readyCount > 0 + retryWaitCount > 0 triggers (retry_wait_pending only applies when readyCount=0)', () => {
|
|
18
|
-
const input = makeInput({
|
|
19
|
-
lastActivityAt: new Date(NOW_MS - 600_000).toISOString(),
|
|
20
|
-
queue: { readyCount: 1, pendingCount: 1, retryWaitCount: 5 },
|
|
21
|
-
});
|
|
22
|
-
const result = evaluateIdleTrigger(input);
|
|
23
|
-
expect(result.decision).toBe('trigger');
|
|
24
|
-
expect(result.reason).toBe('idle_threshold_met');
|
|
25
|
-
});
|
|
26
|
-
it('readyCount > 0 + retryWaitCount === 0 triggers idle_threshold_met', () => {
|
|
27
|
-
const input = makeInput({
|
|
28
|
-
lastActivityAt: new Date(NOW_MS - 600_000).toISOString(),
|
|
29
|
-
queue: { readyCount: 1, pendingCount: 1, retryWaitCount: 0 },
|
|
30
|
-
});
|
|
31
|
-
const result = evaluateIdleTrigger(input);
|
|
32
|
-
expect(result.decision).toBe('trigger');
|
|
33
|
-
expect(result.reason).toBe('idle_threshold_met');
|
|
34
|
-
});
|
|
35
|
-
it('readyCount = 0 + retryWaitCount > 0 returns skip retry_wait_pending', () => {
|
|
36
|
-
const input = makeInput({
|
|
37
|
-
lastActivityAt: new Date(NOW_MS - 600_000).toISOString(),
|
|
38
|
-
queue: { readyCount: 0, pendingCount: 5, retryWaitCount: 3 },
|
|
39
|
-
});
|
|
40
|
-
const result = evaluateIdleTrigger(input);
|
|
41
|
-
expect(result.decision).toBe('skip');
|
|
42
|
-
expect(result.reason).toBe('retry_wait_pending');
|
|
43
|
-
});
|
|
44
|
-
it('readyCount = 0 + retryWaitCount = 0 returns skip no_ready_tasks', () => {
|
|
45
|
-
const input = makeInput({
|
|
46
|
-
lastActivityAt: new Date(NOW_MS - 600_000).toISOString(),
|
|
47
|
-
queue: { readyCount: 0, pendingCount: 0, retryWaitCount: 0 },
|
|
48
|
-
});
|
|
49
|
-
const result = evaluateIdleTrigger(input);
|
|
50
|
-
expect(result.decision).toBe('skip');
|
|
51
|
-
expect(result.reason).toBe('no_ready_tasks');
|
|
52
|
-
});
|
|
53
|
-
it('large readyCount still triggers correctly', () => {
|
|
54
|
-
const input = makeInput({
|
|
55
|
-
lastActivityAt: new Date(NOW_MS - 600_000).toISOString(),
|
|
56
|
-
queue: { readyCount: 100, pendingCount: 200, retryWaitCount: 0 },
|
|
57
|
-
});
|
|
58
|
-
const result = evaluateIdleTrigger(input);
|
|
59
|
-
expect(result.decision).toBe('trigger');
|
|
60
|
-
expect(result.queue.readyCount).toBe(100);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
describe('idle duration edge cases', () => {
|
|
64
|
-
it('idleForMs exactly at idleThresholdMs boundary triggers', () => {
|
|
65
|
-
const { idleThresholdMs } = DEFAULT_IDLE_TRIGGER_CONFIG;
|
|
66
|
-
const input = makeInput({
|
|
67
|
-
lastActivityAt: new Date(NOW_MS - idleThresholdMs).toISOString(),
|
|
68
|
-
queue: { readyCount: 1, pendingCount: 0, retryWaitCount: 0 },
|
|
69
|
-
});
|
|
70
|
-
const result = evaluateIdleTrigger(input);
|
|
71
|
-
expect(result.decision).toBe('trigger');
|
|
72
|
-
});
|
|
73
|
-
it('idleForMs just below idleThresholdMs returns skip not_idle_enough', () => {
|
|
74
|
-
const { idleThresholdMs } = DEFAULT_IDLE_TRIGGER_CONFIG;
|
|
75
|
-
const input = makeInput({
|
|
76
|
-
lastActivityAt: new Date(NOW_MS - idleThresholdMs + 1).toISOString(),
|
|
77
|
-
queue: { readyCount: 1, pendingCount: 0, retryWaitCount: 0 },
|
|
78
|
-
});
|
|
79
|
-
const result = evaluateIdleTrigger(input);
|
|
80
|
-
expect(result.decision).toBe('skip');
|
|
81
|
-
expect(result.reason).toBe('not_idle_enough');
|
|
82
|
-
});
|
|
83
|
-
it('very long idle duration still triggers', () => {
|
|
84
|
-
const input = makeInput({
|
|
85
|
-
lastActivityAt: new Date(NOW_MS - 86_400_000).toISOString(),
|
|
86
|
-
queue: { readyCount: 1, pendingCount: 0, retryWaitCount: 0 },
|
|
87
|
-
});
|
|
88
|
-
const result = evaluateIdleTrigger(input);
|
|
89
|
-
expect(result.decision).toBe('trigger');
|
|
90
|
-
expect(result.idleForMs).toBe(86_400_000);
|
|
91
|
-
});
|
|
92
|
-
it('idleForMs = 0 (just now) returns skip not_idle_enough', () => {
|
|
93
|
-
const input = makeInput({
|
|
94
|
-
lastActivityAt: NOW,
|
|
95
|
-
queue: { readyCount: 1, pendingCount: 0, retryWaitCount: 0 },
|
|
96
|
-
});
|
|
97
|
-
const result = evaluateIdleTrigger(input);
|
|
98
|
-
expect(result.decision).toBe('skip');
|
|
99
|
-
expect(result.reason).toBe('not_idle_enough');
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
describe('activityCooldown boundary conditions', () => {
|
|
103
|
-
it('idleForMs exactly at activityCooldownMs returns skip not_idle_enough', () => {
|
|
104
|
-
const { activityCooldownMs } = DEFAULT_IDLE_TRIGGER_CONFIG;
|
|
105
|
-
const input = makeInput({
|
|
106
|
-
config: { ...DEFAULT_IDLE_TRIGGER_CONFIG },
|
|
107
|
-
lastActivityAt: new Date(NOW_MS - activityCooldownMs).toISOString(),
|
|
108
|
-
queue: { readyCount: 1, pendingCount: 0, retryWaitCount: 0 },
|
|
109
|
-
});
|
|
110
|
-
const result = evaluateIdleTrigger(input);
|
|
111
|
-
expect(result.decision).toBe('skip');
|
|
112
|
-
expect(result.reason).toBe('not_idle_enough');
|
|
113
|
-
});
|
|
114
|
-
it('idleForMs slightly above activityCooldownMs but below idleThresholdMs returns skip not_idle_enough', () => {
|
|
115
|
-
const activityCooldownMs = 60_000;
|
|
116
|
-
const idleThresholdMs = 300_000;
|
|
117
|
-
const input = makeInput({
|
|
118
|
-
config: { ...DEFAULT_IDLE_TRIGGER_CONFIG, activityCooldownMs, idleThresholdMs },
|
|
119
|
-
lastActivityAt: new Date(NOW_MS - activityCooldownMs - 1).toISOString(),
|
|
120
|
-
queue: { readyCount: 1, pendingCount: 0, retryWaitCount: 0 },
|
|
121
|
-
});
|
|
122
|
-
const result = evaluateIdleTrigger(input);
|
|
123
|
-
expect(result.decision).toBe('skip');
|
|
124
|
-
expect(result.reason).toBe('not_idle_enough');
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
describe('lastActivityAt variations', () => {
|
|
128
|
-
it('lastActivityAt undefined with no ready tasks returns skip no_ready_tasks', () => {
|
|
129
|
-
const input = makeInput({
|
|
130
|
-
lastActivityAt: undefined,
|
|
131
|
-
queue: { readyCount: 0, pendingCount: 0, retryWaitCount: 0 },
|
|
132
|
-
});
|
|
133
|
-
const result = evaluateIdleTrigger(input);
|
|
134
|
-
expect(result.decision).toBe('skip');
|
|
135
|
-
expect(result.reason).toBe('no_ready_tasks');
|
|
136
|
-
});
|
|
137
|
-
it('lastActivityAt very old date triggers correctly', () => {
|
|
138
|
-
const input = makeInput({
|
|
139
|
-
lastActivityAt: '2020-01-01T00:00:00.000Z',
|
|
140
|
-
queue: { readyCount: 1, pendingCount: 0, retryWaitCount: 0 },
|
|
141
|
-
});
|
|
142
|
-
const result = evaluateIdleTrigger(input);
|
|
143
|
-
expect(result.decision).toBe('trigger');
|
|
144
|
-
});
|
|
145
|
-
it('lastActivityAt future date (edge case) returns large idleForMs but still triggers', () => {
|
|
146
|
-
const futureTime = new Date(NOW_MS + 1000).toISOString();
|
|
147
|
-
const input = makeInput({
|
|
148
|
-
lastActivityAt: futureTime,
|
|
149
|
-
queue: { readyCount: 1, pendingCount: 0, retryWaitCount: 0 },
|
|
150
|
-
});
|
|
151
|
-
const result = evaluateIdleTrigger(input);
|
|
152
|
-
expect(result.decision).toBe('skip');
|
|
153
|
-
expect(result.reason).toBe('not_idle_enough');
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
describe('config edge cases', () => {
|
|
157
|
-
it('idleThresholdMs = 0 triggers when idleForMs exceeds activityCooldownMs', () => {
|
|
158
|
-
const input = makeInput({
|
|
159
|
-
config: { ...DEFAULT_IDLE_TRIGGER_CONFIG, idleThresholdMs: 0 },
|
|
160
|
-
lastActivityAt: new Date(NOW_MS - 120000).toISOString(),
|
|
161
|
-
queue: { readyCount: 1, pendingCount: 0, retryWaitCount: 0 },
|
|
162
|
-
});
|
|
163
|
-
const result = evaluateIdleTrigger(input);
|
|
164
|
-
expect(result.decision).toBe('trigger');
|
|
165
|
-
});
|
|
166
|
-
it('activityCooldownMs = 0 has no effect on idle threshold check', () => {
|
|
167
|
-
const input = makeInput({
|
|
168
|
-
config: { ...DEFAULT_IDLE_TRIGGER_CONFIG, activityCooldownMs: 0, idleThresholdMs: 1000 },
|
|
169
|
-
lastActivityAt: new Date(NOW_MS - 500).toISOString(),
|
|
170
|
-
queue: { readyCount: 1, pendingCount: 0, retryWaitCount: 0 },
|
|
171
|
-
});
|
|
172
|
-
const result = evaluateIdleTrigger(input);
|
|
173
|
-
expect(result.decision).toBe('skip');
|
|
174
|
-
expect(result.reason).toBe('not_idle_enough');
|
|
175
|
-
});
|
|
176
|
-
it('very large idleThresholdMs returns skip not_idle_enough', () => {
|
|
177
|
-
const input = makeInput({
|
|
178
|
-
config: { ...DEFAULT_IDLE_TRIGGER_CONFIG, idleThresholdMs: 86400000 },
|
|
179
|
-
lastActivityAt: new Date(NOW_MS - 600000).toISOString(),
|
|
180
|
-
queue: { readyCount: 1, pendingCount: 0, retryWaitCount: 0 },
|
|
181
|
-
});
|
|
182
|
-
const result = evaluateIdleTrigger(input);
|
|
183
|
-
expect(result.decision).toBe('skip');
|
|
184
|
-
expect(result.reason).toBe('not_idle_enough');
|
|
185
|
-
});
|
|
186
|
-
it('jitterMaxMs = 0 results in jitterMs = 0', () => {
|
|
187
|
-
const input = makeInput({
|
|
188
|
-
config: { ...DEFAULT_IDLE_TRIGGER_CONFIG, jitterMaxMs: 0 },
|
|
189
|
-
lastActivityAt: new Date(NOW_MS - 600000).toISOString(),
|
|
190
|
-
queue: { readyCount: 1, pendingCount: 0, retryWaitCount: 0 },
|
|
191
|
-
});
|
|
192
|
-
const result = evaluateIdleTrigger(input);
|
|
193
|
-
expect(result.jitterMs).toBe(0);
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
describe('nextEligibleAt calculations', () => {
|
|
197
|
-
it('trigger decision includes correct nextEligibleAt timestamp', () => {
|
|
198
|
-
const input = makeInput({
|
|
199
|
-
config: { ...DEFAULT_IDLE_TRIGGER_CONFIG, idleThresholdMs: 300000, jitterMaxMs: 30000 },
|
|
200
|
-
lastActivityAt: new Date(NOW_MS - 600000).toISOString(),
|
|
201
|
-
queue: { readyCount: 1, pendingCount: 0, retryWaitCount: 0 },
|
|
202
|
-
});
|
|
203
|
-
const result = evaluateIdleTrigger(input);
|
|
204
|
-
expect(result.decision).toBe('trigger');
|
|
205
|
-
expect(result.nextEligibleAt).toBeTruthy();
|
|
206
|
-
expect(new Date(result.nextEligibleAt).getTime()).toBeGreaterThan(NOW_MS);
|
|
207
|
-
});
|
|
208
|
-
it('retry_wait_pending decision includes nextEligibleAt in future', () => {
|
|
209
|
-
const input = makeInput({
|
|
210
|
-
queue: { readyCount: 0, pendingCount: 0, retryWaitCount: 5 },
|
|
211
|
-
});
|
|
212
|
-
const result = evaluateIdleTrigger(input);
|
|
213
|
-
expect(result.decision).toBe('skip');
|
|
214
|
-
expect(result.reason).toBe('retry_wait_pending');
|
|
215
|
-
expect(new Date(result.nextEligibleAt).getTime()).toBeGreaterThan(NOW_MS);
|
|
216
|
-
});
|
|
217
|
-
it('disabled returns nextEligibleAt = now', () => {
|
|
218
|
-
const input = makeInput({
|
|
219
|
-
config: { ...DEFAULT_IDLE_TRIGGER_CONFIG, enabled: false },
|
|
220
|
-
});
|
|
221
|
-
const result = evaluateIdleTrigger(input);
|
|
222
|
-
expect(result.nextEligibleAt).toBe(NOW);
|
|
223
|
-
});
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
//# sourceMappingURL=idle-trigger-edge-cases.test.js.map
|