# Phase 2: Scanners - Context

**Gathered:** 2026-02-26
**Status:** Ready for planning

<domain>
## Phase Boundary

All six scanner classes (PIIScanner, TopicScanner, ToxicityScanner, CyberScanner, JailbreakScanner) implemented with scoped label enums, wired into Guard.scan_input() end-to-end. scan_output() raises NotImplementedError. Placeholder cache (vault) and deanonymize are Phase 3.

</domain>

<decisions>
## Implementation Decisions

### Scanner configuration DX
- Default action + optional per-label overrides: `PIIScanner(labels=[...], action=Action.REPLACE, overrides={PIILabel.SSN: Action.BLOCK})`
- Labels are required — no labels raises an error. Add an `ALL` flag to each scanner's label enum for "scan everything"
- Condition (ANY/ALL/K_OF/CONTEXTUAL) is set per scanner, not per label
- Optional threshold parameter supported: `PIIScanner(labels=[...], threshold=0.8)`

### Risk bundle design
- Bundles (PII, PHI, PCI, SECRETS, TECH) are PIIScanner-only — other scanners don't need bundles
- When a bundle overlaps with an explicit label override, the explicit label wins
- Bundles are not programmatically inspectable — developers use docs to see bundle contents

### Result consumption patterns
- Status field has three values: `blocked`, `secured`, `clean` — no additional convenience properties
- Both overall status and per-scanner results are valid access patterns — document both
- Risk categories exposed at top-level only (as returned by server)

### Multi-scanner behavior
- Single HTTP call with all guardline_specs merged — all scanners processed in one server request
- Server resolves overall status; per-scanner breakdown lets developers make their own decisions per scanner
- Multiple instances of the same scanner type are allowed (e.g., two PIIScanners with different configs)

### Claude's Discretion
- Bundle implementation approach (special enum values vs separate parameter)
- Scanner key format in results dict (guardline ID vs class name remapping)
- Detection label format in results (raw string vs mapped enum)
- Risk categories structure (top-level list pass-through)
- Scanner ordering semantics (or lack thereof)

</decisions>

<specifics>
## Specific Ideas

- Developer looked at server code and confirmed the 5-stage pipeline (Recognize → Validate → Score → Gate → Act) drives the result structure
- Server returns `status`, `processed_text`, `placeholders`, `level`, `scanners` (per-guardline), `risk_categories` — SDK parses directly into ScanResult via Pydantic
- Each scanner's `to_guardline_spec()` produces the server's guardline format: condition, action, level, types (regex/ner/tc), required labels, allowlist, bundles, k
- JailbreakScanner depends on jailbreak TC head which is "coming soon" on server — may need stub

</specifics>

<deferred>
## Deferred Ideas

None — discussion stayed within phase scope

</deferred>

---

*Phase: 02-scanners*
*Context gathered: 2026-02-26*
