timmy-talking-turd/tests/escalation-wiring.test.js
Timmy 693e023758
All checks were successful
Quality gates / quality (pull_request) Successful in 3m31s
fix: replace urgent regex patches with auditable expression grammar
Second hostile review of 1aadca91 found nine ordinary urgent phrasings
bypassing the deterministic gate at detector and service layers, plus
punctuation-fragile contextual exclusions. Replace the accumulated
narrow regex table with a structured, versioned, frozen urgent-expression
grammar and one shared surface normalizer:

- normalizeUrgentText: case folding, apostrophe unification, contraction
  expansion (can't/cant/can not -> cannot, haven't -> have not, ...),
  hyphen splitting, punctuation stripping, whitespace collapse
- URGENT_EXPRESSION_GRAMMAR v2.0: per-flag ordered match expressions with
  bounded nonclinical anchor exclusions; anchors veto only the occurrence
  they sit beside (36-char window), so arbitrary future symptom language
  keeps escalating with no continuation-word allowlist
- new RED->GREEN coverage at every layer: 9 review phrases + 5 prior
  phrases with tense/plural/pronoun/word-order/case/contraction/
  punctuation variants, normalization-equivalence groups, anti-allowlist
  continuation sweep (147 combos), grammar structure audit, service
  zero-Hermes-call interception, and live-HTTP wiring proof with the
  bounded fake adapter (tests/escalation-http.test.js)

Gates: npm test 99/99, check:syntax, check:diff, audit 0 vulns,
staging-deploy 20/20, test:ui/test:photo/test:sleek against this
checkout. No merge, no deploy.
2026-08-22 23:24:51 +00:00

84 lines
4.0 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
const packagePath = new URL('../package.json', import.meta.url);
const domainPath = new URL('../src/domain.js', import.meta.url);
const servicePath = new URL('../src/hermes-agent-service.js', import.meta.url);
const appPath = new URL('../app.js', import.meta.url);
test('expanded escalation suites are first-class gates in the default npm test run', async () => {
const packageJson = JSON.parse(await readFile(packagePath, 'utf8'));
const script = packageJson.scripts.test;
assert.match(script, /tests\/symptom-escalation\.regression\.test\.js/, 'domain regression matrix must run in CI');
assert.match(script, /tests\/escalation-boundary\.test\.js/, 'authoritative boundary suite must run in CI');
});
test('the authoritative zero-Hermes-call invariant stays wired at the single chat gate', async () => {
const [service, app] = await Promise.all([
readFile(servicePath, 'utf8'),
readFile(appPath, 'utf8'),
]);
// Server: urgent detection happens before any Hermes turn is spawned.
const chatIndex = service.indexOf('async chat(');
assert.ok(chatIndex > 0, 'chat entry point exists');
const chatBody = service.slice(chatIndex);
const urgentGate = chatBody.indexOf('detectUrgentText(message).urgent || hasUrgentLedgerContext(ledger)');
const runTurnCall = chatBody.indexOf('await runTurn(');
assert.ok(urgentGate > 0, 'service must screen message and ledger urgency');
assert.ok(runTurnCall > 0, 'service must call the agent adapter');
assert.ok(urgentGate < runTurnCall, 'urgent override must execute before the Hermes turn');
assert.match(chatBody, /safetyOverride: true/, 'override response is explicit');
// Browser: the same deterministic rules intercept before the network call.
assert.match(app, /detectUrgentText\(message\)\.urgent\|\|hasUrgentLedgerContext\(ledgerForAgent\(\)\)/);
assert.match(app, /urgentChatMessage/);
});
test('detection logic stays centralized in the shared domain module', async () => {
const domain = await readFile(domainPath, 'utf8');
// One frozen expression grammar drives text detection; no parallel detector copies exist.
assert.match(domain, /const URGENT_EXPRESSION_GRAMMAR = Object\.freeze\(/);
assert.match(domain, /const URGENT_KEYS = /);
assert.equal([...domain.matchAll(/URGENT_MESSAGE/g)].length >= 3, true,
'flags, ledger, and chat paths share one urgent copy constant');
});
// Second hostile review: the HTTP wiring layer must prove every new phrase is
// intercepted over a live socket before any Hermes adapter process can start.
const WIRING_REVIEW_PHRASES = [
'My stool had blood.',
'My stools are bloody.',
'My stools are black.',
'My stool has turned black.',
'My abdominal pain is severe.',
'Pain in my abdomen is severe.',
'I threw my lunch up.',
'I can not pass gas.',
"I haven't been able to pass gas.",
'yellow-fever outbreak in history class',
'The fever-tree is a plant',
'I threw up, my hands in surrender.',
'Saturday Night Fever won awards',
];
test('urgent review phrases and contextual controls are wired through one shared domain grammar', async () => {
const [service, app] = await Promise.all([
readFile(servicePath, 'utf8'),
readFile(appPath, 'utf8'),
]);
// Server gate screens the message through detectUrgentText before spawning Hermes.
const chatIndex = service.indexOf('async chat(');
const chatBody = service.slice(chatIndex);
assert.ok(chatBody.indexOf('detectUrgentText(message).urgent') > 0);
assert.ok(chatBody.indexOf('detectUrgentText(message).urgent') < chatBody.indexOf('await runTurn('));
// Browser gate re-exports the same detection for pre-network interception.
assert.match(app, /detectUrgentText\(message\)\.urgent/);
assert.match(app, /urgentChatMessage/);
// The grammar lives only in the domain module; the service layer never
// re-implements symptom vocabulary of its own.
assert.doesNotMatch(service, /fever|pass gas|stool|vomit/i);
});