Repository navigation
feat(machine-health): add the state writer, run lock and sync-root guard - #8925
Conversation
…nd sync-root guard Write-StateFile is the only writer of approvals.json and mutes.json: temp file in the same directory, flushed, then File.Replace, or a move without overwrite for the first write with one re-read and re-apply when the file appears meanwhile. Set-ApprovalState applies mute, unmute, approve and revoke under state/approvals.lock and validates the schema before the replace. Enter-RunLock holds a named lock file; Assert-StateBaseLocation reports a path under a OneDrive root or a cloud-attributed reparse point. The TODO.md migration now writes through Write-StateFile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…add unmute and revoke The orchestrator takes state/run.lock; a second run reports one UNKNOWN run-lock result and writes nothing. A state folder under a cloud sync root still gets the checks and the report, plus one UNKNOWN state-location result, but no directory, lock, run log, approvals read, latest.json, history, battery report or TODO.md write; a synced report folder warns. Setup apply writes approvals and mutes only through Set-ApprovalState and gains revoke= and unmute=; approvals.md states that hand edits are unsupported while an audit or setup session runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he state writer The orchestrator holds run.lock inside try/finally, waits up to 2 s for it, and builds both its normal and its held-lock output through New-RunSnapshot, so the held-lock exit emits a complete snapshot. Synced-mode log lines use Write-MachineHealthLog's new -ToStderr switch instead of a redefinition. Set-ApprovalState derives remediation ids from the shipped scripts (Get-RemediationId), leaves key validation to the schema and the unmute lookup, and stamps times after taking the lock. Write-StateFile reads through Read-SharedText and names the temp file in every replace failure; it and Enter-RunLock share Get-InnerHResult. The sync-root attribute rule now warns only; the OneDrive variables alone refuse state writes. New orchestrator tests cover the held lock, a throw after the lock, and synced mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…remediations at setup approvals.md now holds the single statement of who writes approvals.json and mutes.json and what a write guarantees; setup SKILL.md and the script headers cite it. remediation-policy.md approves and revokes through /machine-health:setup apply instead of hand edits. The changelog fragment names the report exemption and the warn-only attribute rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
claude-security-review reviewed No security findings in the incremental diff (e49498f → 2ad5a03). I read
|
|
claude-review reviewed Incremental review of 2ad5a03 (since e49498f)No findings. I reviewed the three changed files by reading
PR context
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e49498f9fb
ℹ️ 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".
…up hint budget The orchestrator saved nothing before binding Write-MachineHealthLog's LogPath and ToStderr defaults into the caller's $PSDefaultParameterValues, so a synced run left later runs in the same session logging to stderr. It now records the prior values and restores them in the existing finally; a test runs a synced and then a writable run in one session and checks the second run's log. The setup argument-hint is shortened to 90 characters with the full set in the Arguments line, and a comment no longer reads as a deferred-work marker. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No related issue: Phase 3 of the owner-approved machine-health PC-checkup plan (ADR 0081, #8906; builds on #8917).
Summary
This PR adds four things:
approvals.jsonandmutes.json: an atomic replace under a lock;applypaths forunmute=andrevoke=.The decision-page picks, the elevated-pass import and the monthly run all write through this path in later phases.
Fix
lib/Write-StateFile.ps1writes approvals.json and mutes.json:Flush(true), closes it, then callsFile.Replace(tmp, dst, null).File.Movewithout overwrite, becauseFile.Replacethrows when the destination is missing. The .NET reference (https://learn.microsoft.com/dotnet/api/system.io.file.replace) listsFileNotFoundException: "The file described bysourceFileNameordestinationFileNameparameter could not be found."lib/Set-ApprovalState.ps1appliesmute,unmute,approveandrevoke:state/approvals.lock, a lock separate fromrun.lock, across the read, change and replace.lib/Get-RemediationId.ps1, and a sync test checks them againstscripts/windows/remediations/.lib/Enter-RunLock.ps1(withlib/Get-InnerHResult.ps1):run.lockexclusively, waiting up to 2 s.run-lockUNKNOWN result inside a full RunSnapshot (lib/New-RunSnapshot.ps1) and writes nothing.lib/Assert-StateBaseLocation.ps1: a state folder under a OneDrive variable prefix runs with every state write suppressed, and only the markdown report is written. In that mode there is no lock, folder, log, latest.json, history, approvals read, migration or remediation. Log lines go to stderr throughWrite-MachineHealthLog -ToStderr.Get-ApprovalStatenow writes throughWrite-StateFile.approvals.mdstates the writer rule once, and the other docs cite it.remediation-policy.mdpoints tosetup apply approve=/revoke=instead of telling users to hand-edit.SKILL.mddocumentsunmute=<key>andrevoke=<remediation>.minor).Consumers found by grep: setup
applywas the only writer named outside the scripts, and it now goes throughSet-ApprovalState. Other writes in the touched scripts:Invoke-MachineHealthCheck.ps1latest.json,history.jsonl, the reportWrite-StateFile.ps1None of the scripts writes
approvals.jsonormutes.jsonother than throughWrite-StateFile.Verification
run-tests.ps1exits 0: 677 passed, 0 failed, 1 skipped.Write-StateFile,Set-ApprovalState,Get-ApprovalState,Enter-RunLock,Assert-StateBaseLocation,Invoke-MachineHealthCheckandWrite-MachineHealthLog.ReadWrite|Deletereader;ReadorReadWritereader.$env:OneDriveset to a folder holding a-StateBaseseeded with TODO.md. The folder listing was identical before and after, the run exited 0, and the report lists onestate-locationUNKNOWN.-DryRun) exits 0.approvals.schema.jsonis byte-identical to main.run.locknot released on a throw), fixed.Related
Follow-up: the
descriptioninapprovals.schema.jsonstill invites hand edits. This PR keeps that schema byte-identical, so the line will be corrected in the planned follow-up PR that edits that schema (service_exclusionswiring,noise_allowlistremoval).🤖 Generated with Claude Code