693e38ffac
An LLM that edits or overwrites a file it never read is acting on hallucinated contents. This plane-2 ToolCallRule blocks it: dispatching on FILE_WRITE (covers file_write and file_edit), a write to a path that exists on disk but was not file_read earlier this session is BLOCKED. A brand-new file passes — you can't read what doesn't exist, and creating is legitimate. - ReadFilesProjection folds the session's file_read events (request + completion, so a failed read doesn't count) into the set of paths read, mirroring EgressAllowlistProjection; threaded into ToolCallAssessmentInput.sessionReadPaths via SessionOrchestrator.resolveSessionReadPaths. - Read paths and the write target are both resolved through the probe (toRealPath), so spelling differences and symlinks can't dodge the gate. - The orchestrator already feeds a block's rationale back as a tool result, so the agent reads the file and retries; the rejected-event reason now carries that rationale too (specific audit trail instead of a generic string). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>