fix(privacy,policy): многострочный Redactor, порядок событий frontmost-veto, перепроверка после await - #68
froggychips wants to merge 1 commit into
Conversation
…r, recheck after await, VAD wiring (review 2026-09-19) Redactor: OCR-строки склеиваются и редактируются одним блоком — PEM из нескольких строк и `password:` со значением на следующей строке теперь матчатся (раньше `redact(_ lines:)` шёл `map`-ом и оба утекали в state.json/ContextStore). Значения в кавычках берутся целиком; card-pattern принимает NBSP/thin-space разделители. WorkspaceEventSource: при activate сначала `.frontmostChanged`, потом `.appActivated` — иначе `freezeTier` на `.appActivated` видел старый frontmostPid и морозил только что активированное приложение, а следующее событие его сразу размораживало (SIGSTOP+pageout+SIGCONT на каждую активацию tier-1 под давлением). VortexCoordinator: `policyGeneration` (инкремент на thawAll/Off/willSleep/ stopMonitoring); `freezeTier` перепроверяет условия перед каждым SIGSTOP и после `await freezeProcess` — если pid стал frontmost, freeze выключен, система уснула или поколение сменилось, SIGCONT сразу и pid не попадает в tier-set (audit outcome `reverted:<причина>`). main.swift: `config.vadEnabled`/`vadRmsThreshold` пробрасываются в координатор (раньше использовались дефолты, поля конфига были мёртвыми). README/SECURITY: честные границы Redactor (e-mail/IBAN не редактируются, транскрипты SessionStore через Redactor не проходят). Тесты добавлены, локально НЕ компилировались (на машине нет XCTest). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wt32A3w8X6bMZAXKSVmsCv
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 523f273c03
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Одно поколение на весь обработчик: thawAll во время обхода tier-1 | ||
| // должен прервать и tier-2, а не только текущий tier (иначе tier-2 | ||
| // взял бы уже новое поколение и доморозил после Off/willSleep). | ||
| let generation = policyGeneration |
There was a problem hiding this comment.
Snapshot the generation before invoking the pacer
When pacerAdjuster suspends, thawAll() or stopMonitoring() can increment policyGeneration before execution reaches this line. The resumed handler then captures the already-incremented value, so every stale-policy check passes and it can freeze processes after the thaw/stop call has returned; cancellation alone does not prevent an async Swift task from continuing. Capture the generation before the pacer await, as the method comment requires, or explicitly revalidate cancellation and lifecycle state afterward.
Useful? React with 👍 / 👎.
| if tier1Frozen.contains(pid) || tier2Frozen.contains(pid) { continue } | ||
| if inFlightFreezes.contains(pid) { continue } |
There was a problem hiding this comment.
Revisit PIDs skipped behind stale in-flight freezes
If an old freeze is in flight when the policy generation changes, a newly valid traversal—for example after stopping and restarting monitoring under sustained pressure—skips that PID here. The old traversal subsequently observes its stale generation, thaws the PID, and returns, while the new traversal has already moved on; because pressure processing is event-driven, the target can remain unfrozen indefinitely despite the current policy. The new traversal needs to wait/retry, or stale completion must trigger reevaluation, rather than permanently skipping an in-flight PID.
Useful? React with 👍 / 👎.
Ревью 2026-09-19, поток «privacy & policy».
Что не так было
Redactor.redact(_ lines:)=lines.map(redact), а Vision отдаёт OCR построчно: многострочный PEM иpassword:со значением на следующей строке не редактировались никогда. ТестtestRedactsPEMBlockпроверял одну многострочную строку, а не массив.WorkspaceEventSourceпри активации шёл.appActivated→.frontmostChanged: координатор запускалfreezeTierсо старымfrontmostPid, замораживал только что активированное приложение, а следующим событием размораживал. Это штатный порядок, не corner-case.freezeTierпослеawait vortex.freezeProcessне перепроверялись frontmost /freezingEnabled/ sleep — Off из меню не останавливал идущий обход.config.vadEnabled/vadRmsThresholdне пробрасывались в координатор.Что сделано
\n), правила с.anchorsMatchLines(пользовательские^…$не ломаются), значения в кавычках берутся целиком, карточный паттерн принимает NBSP/U+202F/U+2009. Тесты на массивы строк.frontmostChangedраньшеappActivated; тест на реальномNSWorkspace-источнике с фильтром по pid теста.policyGenerationна весь обработчик (оба tier'а),inFlightFreezes, перепроверка после каждогоawaitс откатом и auditreverted:<причина>. Тесты с детерминированными «воротами» вместо sleep.SessionStoreчерез Redactor не проходят).Проверка. Собрано локально (
swift build --product FroggyDaemon/froggy/FroggyAudioWorker, только CommandLineTools) без ошибок и предупреждений в изменённых файлах. Тесты не компилировались и не запускались: на машине нет XCTest (нет Xcode), self-hosted раннерjabbook-air-m3offline,ci.ymlна macos-latest давно startup_failure. Diff прошёл ревью Codex, замечания учтены. Перед мержем нуженmake testна машине с Xcode.🤖 Generated with Claude Code
https://claude.ai/code/session_01Wt32A3w8X6bMZAXKSVmsCv