106 lines
3.8 KiB
TypeScript
106 lines
3.8 KiB
TypeScript
/**
|
|
* verifyChatCopilotContract.ts
|
|
*
|
|
* Static contract checks for the chat copilot surface.
|
|
* Verifies the supported action set, runtime-context prompt contract,
|
|
* and safe quick-link guidance without starting the backend server.
|
|
*/
|
|
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { dirname, join } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const apiServerSource = readFileSync(join(__dirname, 'src/services/apiServer.ts'), 'utf8');
|
|
|
|
function assertSourceIncludes(fragment: string, message: string) {
|
|
assert.ok(apiServerSource.includes(fragment), message);
|
|
}
|
|
|
|
function assertSourceMatches(pattern: RegExp, message: string) {
|
|
assert.match(apiServerSource, pattern, message);
|
|
}
|
|
|
|
function testChatRouteRequiresAuth() {
|
|
assertSourceMatches(
|
|
/this\.app\.post\('\/api\/chat',\s*this\.requireAuth,/,
|
|
'/api/chat must be protected by requireAuth',
|
|
);
|
|
console.log('[PASS] /api/chat requires authenticated requests.');
|
|
}
|
|
|
|
function testChatActionContract() {
|
|
for (const action of [
|
|
'create_profile',
|
|
'update_profile',
|
|
'recommend_profile_change',
|
|
'recommend_trade_plan',
|
|
'recommend_reconciliation_followup',
|
|
'review_recent_trades',
|
|
'explain',
|
|
'explain_position',
|
|
'explain_waiting',
|
|
'explain_blocker',
|
|
'summarize_reconciliation',
|
|
]) {
|
|
assertSourceIncludes(`'${action}'`, `chat copilot must support ${action}`);
|
|
}
|
|
|
|
assertSourceIncludes(
|
|
'"action": "create_profile" | "update_profile" | "recommend_profile_change" | "recommend_trade_plan" | "recommend_reconciliation_followup" | "review_recent_trades" | "explain" | "explain_position" | "explain_waiting" | "explain_blocker" | "summarize_reconciliation"',
|
|
'chat prompt contract must document the full action enum',
|
|
);
|
|
console.log('[PASS] chat action contract is documented and supported.');
|
|
}
|
|
|
|
function testQuickLinkContract() {
|
|
assertSourceIncludes(
|
|
`"quickLinks": [{ kind: "portfolio" | "plans" | "settings", ... }] (optional safe in-app destinations)`,
|
|
'chat prompt contract must document quickLinks',
|
|
);
|
|
assertSourceIncludes(
|
|
'Include safe "nextActions" and "quickLinks" whenever they would help the user move to the right app surface.',
|
|
'chat prompt rules must require safe nextActions/quickLinks guidance',
|
|
);
|
|
assertSourceIncludes(
|
|
"{ kind: 'plans', label: 'Manage in Plans'",
|
|
'chat copilot must be able to deep-link into Trade Plans',
|
|
);
|
|
assertSourceIncludes(
|
|
"{ kind: 'settings', label: 'Open Admin Panel', section: 'Admin Panel' }",
|
|
'chat copilot must be able to deep-link into the admin panel',
|
|
);
|
|
assertSourceIncludes(
|
|
"{ kind: 'portfolio', label: 'Open Portfolio'",
|
|
'chat copilot must be able to deep-link into Portfolio',
|
|
);
|
|
console.log('[PASS] quick-link contract is covered.');
|
|
}
|
|
|
|
function testRuntimeCopilotFallbacks() {
|
|
assertSourceIncludes(
|
|
'this.buildTradePlanRecommendation(message, context)',
|
|
'local fallback must support trade-plan recommendations',
|
|
);
|
|
assertSourceIncludes(
|
|
'return this.buildReconciliationFollowup(context);',
|
|
'local fallback must support reconciliation follow-up guidance',
|
|
);
|
|
assertSourceIncludes(
|
|
'this.buildRecentTradeReview(context)',
|
|
'local fallback must support recent-trade review guidance',
|
|
);
|
|
console.log('[PASS] runtime copilot fallback intents are covered.');
|
|
}
|
|
|
|
function main() {
|
|
testChatRouteRequiresAuth();
|
|
testChatActionContract();
|
|
testQuickLinkContract();
|
|
testRuntimeCopilotFallbacks();
|
|
console.log('Chat copilot contract checks passed');
|
|
}
|
|
|
|
main();
|