think
16px
820px

Audit guardrail refusals as status: "refused" — plan

Design: ../specs/2026-07-09-refusal-audit-status-design.md. TDD; pnpm check
green; ship DORMANT (AUDIT_REDIS_URL unset); no deploy without Efran's
explicit go-ahead
.

  1. packages/orchestrator-types/plan.tsRefusalCode union + optional
    code on Refusal.
  2. guards/input-patterns.ts — import canonical Refusal (drop the local
    dup); set code (PII vs entity) on each L1 refusal.
  3. steps/plan.tsNO_TOOLS, GUARDRAIL_PLAN_REFUSED, PLAN_UNPARSEABLE.
  4. lib/audit/emit.ts (new) — buildRefusalEvent (pure) + emitRefusalAudit
    (fire-and-forget XADD; dormant on unset AUDIT_REDIS_URL).
  5. orchestrate.tsturnStartMs; emit in the isRefusal branch (surface,
    userId=sessionId, traceId=turnTraceId, code, total_ms, policy version).
  6. infra/env/public.env.exampleAUDIT_REDIS_URL (dormant) + AUDIT_STREAM.
  7. infra/compose.public.yaml — join external ahu-platform_default network.
  8. Tests — guards codes, plan codes, emit unit, orchestrate integration.

Gate pnpm check; completion + upload. Deploy (public-web image + ahu-public
recreate, leaving AUDIT_REDIS_URL unset) only on go-ahead; the flip + the 4
observatory verification steps are Efran's.