Skip to content

feat(machine-health): add finding items and the read-only mute path - #8917

Merged
kyle-sexton merged 4 commits into
mainfrom
feat/machine-health-finding-items-mutes
Oct 21, 2026
Merged

kyle-sexton merged 4 commits into
mainfrom
feat/machine-health-finding-items-mutes

Conversation

@kyle-sexton

Copy link
Copy Markdown
Member

No related issue: Phase 2 of the owner-approved machine-health PC-checkup plan; implements ADR 0081 (#8906).

Summary

Adds the integration slice that every new list-style check builds on:

  • the FindingItem shape, with a stable FindingKey;
  • the ReadState enum;
  • a read-only state/mutes.json with its own schema;
  • delivery of muted keys to checks as an argument.

A mute keeps an item listed but stops it from raising the check's severity.

Fix

  • lib/New-FindingItem.ps1 adds:
    • Get-FindingKey: <kind>:<first 16 hex of SHA-256(lower(kind|identity))>, over 9 kinds;
    • New-FindingItem;
    • Assert-ReadState;
    • the unmuted severity fold (a ReadState other than ok or absent never folds to OK).
  • New catalog/schemas/mutes.schema.json at 1.0. approvals.schema.json is unchanged byte for byte.
  • lib/Get-MutedFindingKey.ps1 adds Get-MuteState, which is read-only: it creates no folder or file and never migrates TODO.md. It also adds Get-MutedFindingKey.
  • lib/Read-SharedText.ps1 is the one share-delete reader (FileShare ReadWrite|Delete). Get-ApprovalState and Get-MuteState both use it.
  • Get-CheckArgument takes -ScriptPath and returns only the arguments the check script declares. A new check that declares -MutedKeys receives it without a per-id edit, and a check that doesn't declare it is never handed it.
  • Invoke-CheckWithTimeout moves to its own lib file in a separate commit, with its behavior unchanged.
  • The orchestrator reads mutes before the dispatch loop. The approvals read is unchanged.
  • output-schema.md documents the FindingItem detail shape, and approvals.md documents mutes.json.
  • Changelog fragment (minor): a downgraded plugin ignores mutes.json, so muted items raise severity again until the upgrade. Nothing FAILs and nothing is stripped.

Consumers found by grep:

  • Assert-ApprovalState (approvals only, unchanged);
  • Get-ApprovalState (now reads through Read-SharedText);
  • the orchestrator's dispatch;
  • setup check step 3 and approve= (approvals only, unchanged);
  • approvals.md;
  • the two modified test suites.

Verification

  • run-tests.ps1 exits 0: 622 passed, 0 failed, 1 skipped.
  • Filtered suites, each exit 0: New-FindingItem, Get-MutedFindingKey, Get-ApprovalState, Get-CheckArgument, Invoke-CheckWithTimeout and Read-SharedText.
  • The end-to-end case goes through Start-Job: a mute for one item returns muted: true, the item's WARN is ignored by the check severity, and items_count is 2 with muted_count 1.
  • Golden FindingKeys were recomputed independently with sha256sum and with .NET.
  • Host smoke (-DryRun) exits 0: 19 checks ok, 0 failed.
  • The code-design review found 1 CRITICAL, 2 IMPORTANT and 7 SUGGESTION findings. The CRITICAL (a hardcoded per-id mute list), both IMPORTANTs and three suggestions are fixed in 2ca2f2a. A fresh-context phase verifier passed 12 of 12 criteria at 2ca2f2a.

Related

Next phases: the state writer, run lock and sync-root guard; then the storage top-N check, the first check to emit FindingItems.

🤖 Generated with Claude Code

kyle-sexton and others added 3 commits October 21, 2026 15:06
The Start-Job dispatcher moves unchanged from the orchestrator into
scripts/windows/lib so its own suite can run it. The suite covers the
parsed result, a string[] argument crossing the job boundary, and the
timeout, no_output and invalid_json reasons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New-FindingItem.ps1 builds the FindingKey (<kind>:<first 16 hex of the
SHA-256 of the lowercased kind and identity fields>), the FindingItem
shape, the ReadState closed set, and the unmuted severity fold over
Get-WorstSeverity. A read state other than ok or absent never folds to OK.

Mutes live in their own state/mutes.json with a new mutes.schema.json at
1.0; approvals.json and its schema are unchanged. Get-MuteState reads it
with FileShare.ReadWrite | Delete and creates, migrates and logs nothing.
The orchestrator reads it before dispatch and Get-CheckArgument passes
-MutedKeys as a string[] to the eight list-style check ids only.
Get-ApprovalState now reads with the same shared open.

An end-to-end case runs a mute for startup-items through Get-MuteState,
Get-MutedFindingKey, Get-CheckArgument and the Start-Job dispatcher.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Get-CheckArgument takes the check's -ScriptPath and returns only the
candidate arguments the script declares, read from its parameter
metadata, in place of a fixed list of eight check ids. A check that
declares -MutedKeys now receives it with no per-id edit, and a
list-style check can also take -ReportPath or -LogPath.

The share-delete read moves into one helper, Read-SharedText, used by
Get-ApprovalState and Get-MuteState and covered by its own suite.
Get-MuteState finds its schema through Resolve-SkillRoot. The golden
FindingKey tests validate each key inside a mutes.json against
mutes.schema.json, and every accepted kind is checked the same way.
The ReadState set is held in one variable. output-schema.md documents
the FindingItem shape once; approvals.md points to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-21T19:25:48.851565Z 2ca2f2a PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

claude-security-review reviewed 8bb4760e7c4a8768d09946bb3920436269e6382b: 0 finding(s), 0 as inline comments.

No security issues in the incremental change (2ca2f2a..8bb4760).

  • New-FindingItem.ps1: $MutedKeys -ccontains $key became $key -cin $MutedKeys. The two forms are semantically identical, both case-sensitive membership tests. A null or empty $MutedKeys gives $false either way. Mute matching is no looser than before, so nothing is newly muted.
  • Read-SharedText.Tests.ps1: only the non-ASCII test fixture string changed. It is test data and has no runtime or trust-boundary effect.

The change touches no instruction surface, so the instruction-surface lens did not apply. I did not re-review the other files, which are unchanged since the last review.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

claude-review reviewed 8bb4760e7c4a8768d09946bb3920436269e6382b: 0 finding(s), 0 as inline comments.

No findings. I reviewed only the incremental change since 2ca2f2ad, and I did not run the Pester tests.

  • New-FindingItem.ps1:62: $MutedKeys -ccontains $key became $key -cin $MutedKeys. The two operators do the same case-sensitive membership test, so muted-key matching behaves as before. This holds for a null or empty $MutedKeys (both give $false) and for a single-string $MutedKeys. The mute convention still matches exactly on the lowercase key.
  • Read-SharedText.Tests.ps1:12: the fixture text changed from café to étée, which still contains non-ASCII characters. A read that ignored the UTF-8 encoding would still garble it, so the test keeps its purpose. The rewrite looks like it was made to clear the typos lint.

The incremental change touched no other files. The rest of the PR was reviewed at 2ca2f2ad. I did not read the PR context file (.claude-lane/pr-context.md), so I checked this change against no closing-issue criteria.

Use -cin for the case-sensitive mute lookup and a non-word accented
test string, so the repository's typos check passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton added this pull request to the merge queue Oct 21, 2026
Merged via the queue into main with commit 6aa0bba Oct 21, 2026
27 checks passed
@kyle-sexton
kyle-sexton deleted the feat/machine-health-finding-items-mutes branch October 21, 2026 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant