/**
* decision-verify — free verification of the Pillar 3 Rule Library,
* the rule-tool surface, the channel registry, and every Decision
* agent's contract. No Anthropic spend.
*
* npm run decision:verify
*
* Mirrors scripts/intel-verify.ts. Anything green here is a structural
* green light for the paid pipeline; anything red catches issues
* deterministically before a paid run.
*/
import {
loadLibrary,
findRules,
getRule,
resolvePrecedence,
type Rule,
} from '../src/decision/library.js';
import { executeRuleTool, RULE_TOOLS } from '../src/decision/tools.js';
import {
listChannels,
getChannel,
registerChannel,
type Channel,
type DispatchPayload,
} from '../src/decision/channel-registry.js';
import { outputIngestionContract } from '../src/agents/decision/output-ingestion/matrix.js';
import { visualizationContract } from '../src/agents/decision/visualization/matrix.js';
import { deliveryDistributionContract } from '../src/agents/decision/delivery-distribution/matrix.js';
function banner(s: string): void {
console.log(`\n══════════════════════════════════════════════════════════`);
console.log(s);
console.log(`══════════════════════════════════════════════════════════`);
}
function row(label: string, value: unknown): void {
console.log(` ${label.padEnd(22)} ${value}`);
}
function summarise(r: Rule): string {
return `${r.rule_id.padEnd(46)} type=${r.type.padEnd(15)} domain=${r.domain.padEnd(12)} agent=${r.applies_to.agent.padEnd(18)} status=${r.status.padEnd(10)} (${r.sourceFile})`;
}
async function main(): Promise<void> {
const t0 = Date.now();
/* ----------------- 1. Library load ----------------- */
banner('1. Library load (YAML scan + index)');
const all = await loadLibrary();
row('entries loaded:', all.length);
for (const r of all) console.log(` - ${summarise(r)}`);
/* ----------------- 2. Full content of one rule ----------------- */
banner('2. Full content of peer_positioning_recommendation');
const ppr = await getRule('peer_positioning_recommendation');
if (!ppr) {
console.log(' (missing — expected to be present)');
} else {
row('name:', ppr.name);
row('type:', ppr.type);
row('domain:', ppr.domain);
row('agent:', ppr.applies_to.agent);
row('triggers:', ppr.applies_to.triggers.length);
for (const t of ppr.applies_to.triggers) console.log(` • ${t}`);
row('conditions:', ppr.conditions.length);
row('action keys:', Object.keys(ppr.action).join(', '));
row('confidence:', JSON.stringify(ppr.confidence_framework));
row('disclosure:', JSON.stringify(ppr.disclosure_policy ?? null));
row('status:', ppr.status);
row('source file:', ppr.sourceFile);
}
/* ----------------- 3. Sample queries ----------------- */
banner('3. Sample queries (library.ts API)');
const queries: { label: string; query: Parameters<typeof findRules>[0] }[] = [
{ label: 'type=interpretation', query: { type: 'interpretation' } },
{ label: 'type=visualization', query: { type: 'visualization' } },
{ label: 'type=delivery', query: { type: 'delivery' } },
{ label: 'domain=banking', query: { domain: 'banking' } },
{ label: 'domain=insurance (no entries yet)', query: { domain: 'insurance' } },
{ label: 'agent=output_ingestion', query: { agent: 'output_ingestion' } },
{ label: 'agent=visualization', query: { agent: 'visualization' } },
{ label: 'agent=delivery', query: { agent: 'delivery' } },
{ label: 'triggers=["peer_positioning"]', query: { triggers: ['peer_positioning'] } },
{ label: 'triggers=["decision_maker"]', query: { triggers: ['decision_maker'] } },
{ label: 'triggers=["material"]', query: { triggers: ['material'] } },
{ label: 'triggers=["nonsense"] (should be empty)', query: { triggers: ['nonsense'] } },
];
for (const q of queries) {
const hits = await findRules(q.query);
console.log(` ${q.label.padEnd(48)} → ${hits.length} hit(s): ${hits.map(h => h.rule_id).join(', ') || '—'}`);
}
/* ----------------- 4. Precedence resolution ----------------- */
banner('4. Precedence resolution');
const allActive = await findRules({});
const ordered = resolvePrecedence(allActive);
for (const r of ordered) {
console.log(` ${r.rule_id.padEnd(46)} domain=${r.domain.padEnd(8)} triggers=${r.applies_to.triggers.length} declared=${r.declared_date}`);
}
/* ----------------- 5. Anthropic tool descriptors ----------------- */
banner('5. Anthropic tool descriptors (what Decision agents declare to Claude)');
for (const t of RULE_TOOLS) {
console.log(` - ${t.name}`);
console.log(` ${t.description.replace(/\s+/g, ' ').slice(0, 110)}…`);
console.log(` required: [${t.input_schema.required.join(', ')}] properties: [${Object.keys(t.input_schema.properties).join(', ')}]`);
}
/* ----------------- 6. Execute tools ----------------- */
banner('6. executeRuleTool — exercises the dispatcher');
const callA = await executeRuleTool('find_rules', { type: 'interpretation' });
console.log(` find_rules({type:"interpretation"}) → ok=${callA.ok}, ${(callA.result as unknown[] | undefined)?.length ?? 0} hit(s)`);
const callB = await executeRuleTool('find_rules', { triggers: 'decision_maker, peer_positioning' });
console.log(` find_rules({triggers:"decision_maker, peer_positioning"}) → ok=${callB.ok}, ${(callB.result as unknown[] | undefined)?.length ?? 0} hit(s)`);
const callC = await executeRuleTool('get_rule', { rule_id: 'material_decision_maker_alert_delivery' });
const rule = callC.result as Rule | undefined;
console.log(` get_rule("material_decision_maker_alert_delivery") → ok=${callC.ok} name="${rule?.name ?? ''}"`);
const callD = await executeRuleTool('get_rule', { rule_id: 'does_not_exist' });
console.log(` get_rule("does_not_exist") → ok=${callD.ok} error=${callD.error?.category ?? '?'}: ${callD.error?.message ?? ''}`);
const callE = await executeRuleTool('get_rule', {});
console.log(` get_rule({}) → ok=${callE.ok} error=${callE.error?.category ?? '?'}: ${callE.error?.message ?? ''}`);
const callF = await executeRuleTool('unknown_tool', {});
console.log(` unknown_tool({}) → ok=${callF.ok} error=${callF.error?.category ?? '?'}: ${callF.error?.message ?? ''}`);
/* ----------------- 7. Per-agent reachability ----------------- */
banner('7. Which rules each Decision agent can reach today');
const agents = ['output_ingestion', 'visualization', 'delivery'] as const;
for (const a of agents) {
const hits = await findRules({ agent: a });
console.log(` ${a.padEnd(20)} → ${hits.length} reachable rule(s): ${hits.map(h => h.rule_id).join(', ') || '—'}`);
}
console.log(` (any agent whose row is "—" will escalate every relevant request as a rule-gap)`);
/* ----------------- 8. Channel registry ----------------- */
banner('8. Channel registry');
const channels = listChannels();
row('registered:', channels.join(', '));
const auditLog = getChannel('audit-log');
if (auditLog) {
row('audit-log desc:', auditLog.description);
/* Exercise the channel surface — dispatch one payload and read the
* outcome. No external side effect (audit-log is no-op). */
const outcome = await auditLog.dispatch({
recipient: 'audience-tier:decision_maker',
audienceTier: 'decision_maker',
content: { kind: 'verification', data: { hello: 'world' } },
contentReference: 'decision-verify-smoke',
severity: 'normal',
acknowledgmentRequired: true,
acknowledgmentWindowSec: 60,
});
row('test dispatch:', `ok=${outcome.ok} ack=${outcome.acknowledgmentState} channel=${outcome.channel}`);
}
/* Register-then-unregister roundtrip (verifies the API surface). */
const fake: Channel = {
name: '__verify_probe__',
description: 'temporary probe for decision-verify',
async dispatch(_p: DispatchPayload) {
return {
ok: true,
channel: this.name,
dispatchedAt: new Date().toISOString(),
acknowledgmentRequired: false,
acknowledgmentState: 'not-applicable' as const,
};
},
};
registerChannel(fake);
const probe = getChannel('__verify_probe__');
row('register/get probe:', probe ? 'ok' : 'FAILED');
/* Leave probe registered — harmless and proves the API roundtrip;
* the audit-log default remains the rule-named channel. */
/* ----------------- 9. Agent contracts ----------------- */
banner('9. Pillar 3 agent contracts');
for (const c of [outputIngestionContract, visualizationContract, deliveryDistributionContract]) {
console.log(` ${c.agentName.padEnd(34)} v${c.agentVersion}`);
console.log(` pillar: ${c.pillar}`);
console.log(` capabilities: ${c.capabilities.join(', ')}`);
console.log(` runbook: ${c.runbook.length} step(s)`);
console.log(` triggers: ${c.triggers.join(', ')}`);
console.log(` forbidden: ${c.rules.pillarSpecificForbidden.join(', ')}`);
}
console.log(`\nDone. Elapsed: ${((Date.now() - t0) / 1000).toFixed(2)}s. $0 spent.`);
}
main().catch(err => {
console.error('decision-verify failed:', err);
process.exit(1);
});