Files
LWLT-AIBOT/control-plane/test/program-only-routes.test.ts
2026-09-09 17:24:16 +08:00

113 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import test from 'node:test';
import {
BUSINESS_ROUTES,
allowedParserModesForRoute,
effectiveParserModeForRoute,
isParserModeAllowedForRoute,
type ParserMode
} from '../src/business-routes.js';
import { loadConfig } from '../src/config.js';
import { resolveParserModeSnapshot, TaskError, TaskService } from '../src/task-service.js';
const programOnlyRouteIds = [
'shared_child_order_batch_create',
'passenger_list_import_independent',
'passenger_list_import_shared_child'
] as const;
const parserModes: ParserMode[] = ['ai', 'shadow', 'auto', 'program'];
test('the two roster routes and shared-child batch route are hard Program-only in the machine registry', () => {
const programOnly = BUSINESS_ROUTES.filter((route) => route.parserPolicy === 'program_only');
assert.deepEqual(programOnly.map((route) => route.routeId), programOnlyRouteIds);
for (const route of BUSINESS_ROUTES) {
const expectedModes = programOnlyRouteIds.includes(route.routeId as typeof programOnlyRouteIds[number])
? ['program']
: parserModes;
assert.deepEqual(allowedParserModesForRoute(route), expectedModes, route.routeId);
for (const mode of parserModes) {
assert.equal(
isParserModeAllowedForRoute(route, mode),
expectedModes.includes(mode),
`${route.routeId}:${mode}`
);
assert.equal(
effectiveParserModeForRoute(route, mode),
expectedModes.includes(mode) ? mode : 'program',
`${route.routeId}:${mode}:effective`
);
}
}
});
test('hard Program-only task snapshots stay Program with missing or hostile stored settings', async () => {
const routeText = (routeId: typeof programOnlyRouteIds[number]) => {
const route = BUSINESS_ROUTES.find((candidate) => candidate.routeId === routeId);
assert.ok(route);
return `${route.directive}\n单号TEST-ORDER`;
};
for (const routeId of programOnlyRouteIds) {
for (const storedMode of [null, ...parserModes] as const) {
const client = {
async query() {
return storedMode === null
? { rowCount: 0, rows: [] }
: { rowCount: 1, rows: [{ mode: storedMode, revision: 7 }] };
}
};
const snapshot = await resolveParserModeSnapshot(client as never, 'test-org', routeText(routeId));
assert.equal(snapshot.routeId, routeId);
assert.equal(snapshot.mode, 'program');
assert.equal(snapshot.engineAffinity, null);
assert.equal(snapshot.revision, storedMode === null ? 0 : 7);
}
}
const configurableRoute = BUSINESS_ROUTES.find((route) => route.routeId === 'team_order_create');
assert.ok(configurableRoute);
const configurable = await resolveParserModeSnapshot({
async query() {
return { rowCount: 1, rows: [{ mode: 'shadow', revision: 4 }] };
}
} as never, 'test-org', configurableRoute.directive);
assert.equal(configurable.mode, 'shadow');
assert.equal(configurable.revision, 4);
});
test('the public route mutation rejects AI, Shadow, and Auto before touching settings storage', async () => {
const service = new TaskService(loadConfig({
NODE_ENV: 'test',
FIELD_ENCRYPTION_KEY: Buffer.alloc(32, 17).toString('base64'),
DATABASE_URL: 'postgresql://invalid:invalid@127.0.0.1:1/invalid'
}));
const context = { organizationId: 'test-org', userId: 'test-user', requestId: 'test-request' };
for (const routeId of programOnlyRouteIds) {
for (const mode of parserModes.filter((candidate) => candidate !== 'program')) {
await assert.rejects(
service.setParserRoutingMode(context, routeId, mode, 0),
(error: unknown) => error instanceof TaskError
&& error.code === 'parser_mode_not_supported'
&& error.statusCode === 409
&& error.details.parser_policy === 'program_only'
&& Array.isArray(error.details.allowed_modes)
&& error.details.allowed_modes.join(',') === 'program',
`${routeId}:${mode}`
);
}
}
});
test('TaskService exposes and enforces the registry parser policy at every AI override boundary', async () => {
const source = await readFile(new URL('../src/task-service.ts', import.meta.url), 'utf8');
assert.match(source, /allowed_modes:/);
assert.match(source, /parser_policy:/);
assert.match(source, /isParserModeAllowedForRoute\(route, mode\)/);
assert.match(source, /parser_mode_not_supported/);
assert.match(source, /effectiveParserModeForRoute\(route, 'ai'\)/);
assert.match(source, /ai_reparse_not_supported/);
assert.match(source, /enforceFixedParserModeForClaim/);
});