# Isolate proto freshness generation from the scanned repository Decided 2026-08-25. Check 2f ran `make proto` in the scanned CMS working tree and compared `git status` before and after. That made a read-oriented safety check destructive: concurrent checker processes generated into the same files, an interrupted run could leave a partially rewritten tree, and a generated file that was already dirty could change bytes without changing its porcelain status. ## Decision - Copy the proto generation inputs and existing generated outputs into a unique temporary sandbox for every freshness invocation. - Run `make proto` only in that sandbox. Link only the installed package-local generator executables and their package entrypoints needed by Buf and the export script; generated output paths never point back into the scanned repository. - Snapshot generated regular files and symlinks by type, mode, link target, and SHA-256 content digest before and after generation. Sort paths before reporting added, modified, and removed outputs in the existing porcelain-like CLI format. - Remove the owned sandbox on success, generator failure, and all ordinary return paths. Abrupt process interruption can affect only disposable system temporary state, never the scanned working tree. - Exercise the boundary with real `make` recipes, including independent concurrent checker processes and a generator that writes partial output before failing. A repository-wide lock was rejected because it serializes independent safety runs and still leaves the live working tree vulnerable to interrupted generation. Comparing only Git status in a temporary checkout was rejected because status is not a content comparison and can conceal a second rewrite of an already-modified file. Copying the entire repository, including dependency trees and build artifacts, was rejected because proto generation needs only a small, explicit input and output surface. ## Consequences - Parallel check-safety processes can run proto freshness checks without contending on generated files or corrupting the CMS checkout. - Check 2f retains its `make proto` success, failure, and before/after finding messages while its freshness verdict now follows deterministic file content. - Generator stderr is still returned through `protoFreshnessResult.output`, and sandbox preparation, snapshot, generation, and cleanup failures retain their causal error chains. - `proto_freshness.go` owns isolation and comparison; focused regression coverage lives in `proto_freshness_test.go`. Keywords: check-safety, check 2f, proto freshness, make proto, concurrency, interruption safety, sandbox, checkProtoGeneratedFreshness, checkProtoGeneratedFreshnessInSandbox, protoFreshnessResult, proto_freshness.go, proto_freshness_test.go, backend/internal/api, backend/internal/mcpserver/generated, packages/api/src, buf generate, pnpm generate-exports