# Approval AI Refinement

CTM's approval system has two separate jobs:

1. Detect and parse the active terminal approval prompt.
2. Decide whether the requested action is safe to approve.

AI refinement only belongs to the first job. It must never become the approval
policy itself.

## Decision model (2026 update): allow-by-default + denylist

CTM's shadow approver is **allow-by-default**: it auto-approves every detected
prompt EXCEPT commands on the denylist. The denylist is the dangerous-command
**blocklist** (`workers/approval-blocklist.js`) — ON by default and editable in
the Permission Manager / Shadow Approver panel (the "permissions tab"). This is
the single default gate.

`handleApprovalCheck` order: parse → dedup → **blocklist** (escalate if matched)
→ **Permission Manager rules** (user deny → escalate; user allow → approve, skip
verifier) → **verifier** (medium+ risk, if not user-allowed) → **auto-approve**
(one-time keystroke). The AI reviewer (`reviewWithAI`) is no longer in the
default path.

- **Blocklist is the denylist, ON by default.** Seeded with catastrophic /
  irreversible patterns (rm -rf, mkfs, dd, sudo-destructive, reboot/shutdown,
  `> /etc|/usr|/var|/boot`, curl|bash, credential exfil, recursive chmod/chown,
  `git push --force`, `drop/truncate table`, `chmod 777` on system paths,
  destructive `find -exec`, `node -e`/`python -c` with dangerous syscalls). Edit
  it in the panel to add/remove what should require approval.
- **Permission Manager rules are authoritative across providers.** The approver
  honors the user's `perm_rules` (`Bash(node:*)` allow/deny) via
  `lib/permission-match.js` — a **deny** match escalates; an **allow** match
  (without `always_ask`) auto-approves and skips the verifier. These rules
  otherwise only configure Claude Code's own settings.json, so honoring them here
  makes them apply to Codex and every other provider too.
- **Verifier is ON by default (second opinion).** For commands the user has NOT
  explicitly allowed, the LLM verifier runs on **medium+ risk** and can veto an
  auto-approval (read-only/low-risk ops skip it). Provider-agnostic via
  `lib/background-llm.js` (`callBackgroundLlm`); a configured
  `auto_approval_verifier_command` overrides the built-in. Turn off via
  `ctm_settings.auto_approval_verifier_enabled = false`.
- **One-time approvals only.** CTM sends the one-time "yes" keystroke and never
  auto-selects the durable "allow all / don't ask again" option.

## Self-adaptation from user behavior

Beyond detector/parser gate-misses, CTM learns from the user's own corrections
(`lib/approval-self-adapt.js`):

- **Interrupt after auto-approve** (Ctrl-C right after a learned-rule
  auto-approval) → the offending learned rule is retired.
- **Approve after escalation** (user manually approves a prompt CTM escalated) →
  a positive signal is recorded for the history-scan / maintenance loop to
  promote a narrow rule.
- A periodic **`approval-self-adapt`** scheduler job retires active detection
  rules whose patterns no longer compile/are safe, keeping the learned set healthy.

## Problem

The shadow approver can miss a real approval prompt before policy review runs:

- the detector sees approval-shaped text but the structural gate rejects it;
- a provider parser fails to extract the command/tool;
- the terminal snapshot is partial or races with a redraw;
- the provider changed prompt wording.

Previously, the rescue path returned `unparsed` before AI could diagnose the
miss. That made refinement hide behind the parser even when the parser was the
broken component.

## Flow

The refinement loop is:

1. Record the raw missed approval observation.
2. Ask AI to classify the miss and propose a narrow parser/detector rule.
3. Save the candidate rule in `approval_ai_refinement_rules`, separate from
   shipped approval rules and user-learned approval policy rules.
4. Validate the rule locally against the same raw terminal frame:
   - regexes compile and pass safety checks;
   - the one-time Yes/Allow option is matched;
   - command/tool context can be extracted;
   - no durable "always allow" shortcut is selected.
5. If validation passes, mark the rule `active`.
6. Rerun the normal approval rescue path. This proves the new rule participates
   in the same blocklist, policy, live-prompt preflight, keystroke, and
   post-send verification as every other approval.
7. If the rerun works, the rule remains active.
8. If proposal, validation, or rerun fails, persist an open warning in
   `approval_ai_refinement_warnings` and stop. The warning is queryable through
   `/api/approval-ai-refinement/warnings` so it does not disappear if the user
   misses a toast.

## Storage Boundaries

AI generated parser rules are intentionally not stored in `approval_rules`.

- `approval_rules`: user/AI learned approval policy rules for known command
  signatures.
- `approval_rescue_patterns`: retry/cooldown bookkeeping for rescue attempts.
- `approval_ai_refinement_rules`: AI generated parser/detector refinements.
- `approval_ai_refinement_warnings`: persistent warnings when refinement fails.

This keeps product-shipped rules, user policy, and AI-generated parsing
patches auditable and reversible independently.

## Telemetry

When a refinement proposal is evaluated, CTM sends a privacy-safe telemetry
event named `ctm_approval_ai_refinement` through the Wall-E telemetry endpoint.

The event includes:

- provider id;
- source and gate reason;
- miss type;
- validation status;
- confidence;
- booleans for which rule components were proposed;
- a sanitized generated rule payload for detector/question/yes/command-pattern
  structure.

The event does not include raw terminal text, command text, paths, or secrets.
Command-shaped anchors are redacted before upload. Product maintainers can
aggregate these validated rule shapes and use them to improve CTM's shipped
detectors later.

## Safety Rules

Refinement rules are parser rules only:

- they cannot approve anything by themselves;
- they cannot select durable allow-all options;
- active rules are still subject to the dangerous-command blocklist;
- active rules are still subject to normal approval policy review;
- keystrokes are still guarded by live terminal preflight and verification;
- a failed rerun marks the AI rule failed and persists a warning.
