Refactor local memory and role-fixed runtime routing

This commit is contained in:
Eyejoker
2026-04-04 03:50:28 +09:00
parent ca58e8c8eb
commit 3dd772c229
47 changed files with 6158 additions and 669 deletions

View File

@@ -11,7 +11,9 @@ import {
buildVerifySummary,
detectChannelAuth,
detectCredentials,
detectLegacyDiscordTokenKeys,
loadRegisteredGroupsSummary,
loadRoleRoutingRequirementsSummary,
} from './verify-state.js';
describe('verify state helpers', () => {
@@ -34,14 +36,88 @@ describe('verify state helpers', () => {
expect(detectCredentials(tempRoot)).toBe('configured');
});
it('detects channel auth from either env source', () => {
it('detects canonical role-based channel auth names from process env', () => {
expect(
detectChannelAuth(
{ DISCORD_BOT_TOKEN: '' },
{ DISCORD_BOT_TOKEN: 'discord-token' },
{},
{
DISCORD_OWNER_BOT_TOKEN: 'owner-token',
DISCORD_REVIEWER_BOT_TOKEN: 'reviewer-token',
DISCORD_ARBITER_BOT_TOKEN: 'arbiter-token',
},
),
).toEqual({
discord: 'configured',
'discord-review': 'configured',
'discord-arbiter': 'configured',
});
});
it('does not treat legacy service-based channel auth names as configured channels', () => {
expect(
detectChannelAuth(
{},
{
DISCORD_CLAUDE_BOT_TOKEN: 'legacy-owner-token',
DISCORD_CODEX_MAIN_BOT_TOKEN: 'legacy-reviewer-token',
DISCORD_CODEX_REVIEW_BOT_TOKEN: 'legacy-arbiter-token',
},
),
).toEqual({});
});
it('detects legacy service-based discord token names from env file and process env', () => {
expect(
detectLegacyDiscordTokenKeys(
{
DISCORD_BOT_TOKEN: 'legacy-owner-token',
},
{
DISCORD_CODEX_MAIN_BOT_TOKEN: 'legacy-reviewer-token',
DISCORD_CODEX_REVIEW_BOT_TOKEN: 'legacy-arbiter-token',
},
),
).toEqual([
'DISCORD_BOT_TOKEN',
'DISCORD_CODEX_MAIN_BOT_TOKEN',
'DISCORD_CODEX_REVIEW_BOT_TOKEN',
]);
});
it('loads paired-room routing requirements from the sqlite store', () => {
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ejclaw-verify-'));
tempRoots.push(tempRoot);
const dbPath = path.join(tempRoot, 'messages.db');
const db = new Database(dbPath);
db.exec(`
CREATE TABLE registered_groups (
jid TEXT NOT NULL,
agent_type TEXT
);
`);
db.exec(`
CREATE TABLE paired_tasks (
id TEXT PRIMARY KEY,
chat_jid TEXT NOT NULL,
status TEXT NOT NULL
);
`);
db.exec(`
INSERT INTO registered_groups (jid, agent_type) VALUES
('group-1', 'claude-code'),
('group-1', 'codex'),
('group-2', 'claude-code');
`);
db.exec(`
INSERT INTO paired_tasks (id, chat_jid, status) VALUES
('task-1', 'group-1', 'arbiter_requested'),
('task-2', 'group-2', 'completed');
`);
db.close();
expect(loadRoleRoutingRequirementsSummary(dbPath)).toEqual({
tribunalRooms: 1,
activeArbiterTasks: 1,
});
});
@@ -83,13 +159,6 @@ describe('verify state helpers', () => {
launchdLabel: 'com.ejclaw',
logName: 'ejclaw',
},
{
kind: 'codex',
name: 'ejclaw-codex',
description: 'Codex',
launchdLabel: 'com.ejclaw.codex',
logName: 'ejclaw-codex',
},
];
expect(
@@ -97,15 +166,19 @@ describe('verify state helpers', () => {
services,
serviceDefs,
'configured',
{ discord: 'configured' },
{
discord: 'configured',
'discord-review': 'configured',
'discord-arbiter': 'configured',
},
2,
{ codex: 1 },
),
).toMatchObject({
status: 'success',
configuredChannels: ['discord'],
configuredChannels: ['discord', 'discord-review', 'discord-arbiter'],
codexConfigured: true,
reviewConfigured: false,
reviewConfigured: true,
servicesSummary: { ejclaw: 'running' },
});
});
@@ -128,4 +201,95 @@ describe('verify state helpers', () => {
servicesSummary: { ejclaw: 'stopped' },
});
});
it('fails verification when only the review channel is configured', () => {
const services: ServiceCheck[] = [{ name: 'ejclaw', status: 'running' }];
expect(
buildVerifySummary(
services,
[],
'configured',
{ 'discord-review': 'configured' },
1,
{},
),
).toMatchObject({
status: 'failed',
configuredChannels: ['discord-review'],
codexConfigured: true,
reviewConfigured: false,
servicesSummary: { ejclaw: 'running' },
});
});
it('fails verification when tribunal rooms exist but the reviewer channel is missing', () => {
const services: ServiceCheck[] = [{ name: 'ejclaw', status: 'running' }];
expect(
buildVerifySummary(
services,
[],
'configured',
{ discord: 'configured' },
1,
{},
{ tribunalRooms: 1 },
),
).toMatchObject({
status: 'failed',
configuredChannels: ['discord'],
codexConfigured: false,
reviewConfigured: false,
tribunalRooms: 1,
});
});
it('fails verification when arbiter work is pending but the arbiter channel is missing', () => {
const services: ServiceCheck[] = [{ name: 'ejclaw', status: 'running' }];
expect(
buildVerifySummary(
services,
[],
'configured',
{
discord: 'configured',
'discord-review': 'configured',
},
1,
{},
{ tribunalRooms: 1, activeArbiterTasks: 1 },
),
).toMatchObject({
status: 'failed',
configuredChannels: ['discord', 'discord-review'],
codexConfigured: true,
reviewConfigured: false,
activeArbiterTasks: 1,
});
});
it('fails verification when legacy discord token names are still configured', () => {
const services: ServiceCheck[] = [{ name: 'ejclaw', status: 'running' }];
expect(
buildVerifySummary(
services,
[],
'configured',
{
discord: 'configured',
'discord-review': 'configured',
'discord-arbiter': 'configured',
},
1,
{},
{ legacyDiscordTokenKeys: ['DISCORD_BOT_TOKEN'] },
),
).toMatchObject({
status: 'failed',
legacyDiscordTokenKeys: ['DISCORD_BOT_TOKEN'],
});
});
});