You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
AI response handler: the SHADOW_MODE compare still fails open #157
Three pre-existing issues in packages/outpost/queue/src/handlers/ai-response.ts, all verified during the CR of #150 and all outside that PR's subject.
1. escalated: true is reported even when the escalation never enqueued
The escalation createJob is wrapped in a try/catch that logs and continues, but the handler's result still reports escalated: true. So a ticket whose escalation failed to enqueue looks escalated in the job record while no human was ever routed to it — the same "the record disagrees with what happened" class as #148.
2. A null description is stringified as the literal "null"
The classifier prompt interpolates ticket.description directly. Ticket.description is non-null in the schema today, but the AI pipeline path also handles tickets built from partial rows, and the guard costs nothing.
3. SHADOW_MODE === 'true' fails open
The strict comparison means SHADOW_MODE=TRUE, =1, or =yes all read as "not shadow mode" and post to real community surfaces. Shadow mode is a safety flag; it should fail closed on any truthy-looking value it does not recognize, and preferably log the value it rejected. This pattern is repo-wide, so fixing it centrally (a shared isShadowMode() helper) is probably better than patching one call site.
escalated is now derived from escalationEnqueued / escalationSkippedState rather than being reported unconditionally, so a throwing enqueue no longer reports a handoff that did not happen (packages/outpost/queue/src/handlers/ai-response.ts:1084-1085)
the classifier prompt joins only the parts that exist, so a null description no longer stringifies as the literal "null" (ai-response.ts:716-721)
Still open — the one this issue now tracks:process.env.SHADOW_MODE === 'true' remains at ai-response.ts:829 and onboarding-digest.ts:119. The comparison accepts exactly one spelling, so TRUE, 1, yes and on all read as "not shadow mode" and post for real — a safety flag failing open on inputs an operator would reasonably expect to work.
PR #233 replaces both call sites with a shared isShadowMode() that fails closed, and is open and green. This should close when that merges.
changed the title [-]AI response handler: three small correctness gaps (escalation reporting, null description, SHADOW_MODE compare)[/-][+]AI response handler: the SHADOW_MODE compare still fails open[/+]on Sep 15, 2026
Activity
fix(shared): make SHADOW_MODE fail closed
fix(shared): make SHADOW_MODE fail closed
NathanTarbert commentedon Sep 15, 2026
Two of the three gaps here are fixed on
main; retitling so the remaining scope matches what is left.Fixed by #191:
escalatedis now derived fromescalationEnqueued/escalationSkippedStaterather than being reported unconditionally, so a throwing enqueue no longer reports a handoff that did not happen (packages/outpost/queue/src/handlers/ai-response.ts:1084-1085)"null"(ai-response.ts:716-721)Still open — the one this issue now tracks:
process.env.SHADOW_MODE === 'true'remains atai-response.ts:829andonboarding-digest.ts:119. The comparison accepts exactly one spelling, soTRUE,1,yesandonall read as "not shadow mode" and post for real — a safety flag failing open on inputs an operator would reasonably expect to work.PR #233 replaces both call sites with a shared
isShadowMode()that fails closed, and is open and green. This should close when that merges.[-]AI response handler: three small correctness gaps (escalation reporting, null description, SHADOW_MODE compare)[/-][+]AI response handler: the SHADOW_MODE compare still fails open[/+]