Skip to content

feat(machine-health): research new findings in the monthly run, in auto mode - #9670

Merged
kyle-sexton merged 9 commits into
mainfrom
feat/machine-health-discovery-monthly
Oct 24, 2026
Merged

kyle-sexton merged 9 commits into
mainfrom
feat/machine-health-discovery-monthly

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

Summary

The monthly machine-health checkup now researches what is new on the machine, and the unattended run is simpler.

Fix

  • Auto mode. The Task Scheduler wrapper is a static copy that starts claude -p '/machine-health:audit on-demand --scheduled' --permission-mode auto --output-format json with a 90-minute limit. The exact allow rules, the deny settings file (scheduled-settings.json) and the roots written into the copy are gone. schedule removes a settings file an earlier build left. The Desktop route offers Auto only, because research reads different pages each month and a Manual run would stall on prompts.
  • New findings. On a -Scheduled orchestrator run, latest.json gets new_finding_keys: keys absent from the previous run, per check. A check counts as a baseline when its previous entry listed detail.items and was not SKIPPED. latest.json also gets discovery_path (discovery-<runStamp>.md beside the report), which the report and the decision page name.
  • Research. Get-ResearchCandidate.ps1 picks up to 5 new startup entries, logon tasks, extensions, listeners, busy processes or Defender detections. Step 5 makes one /discovery:research breadth=low call over them, writes the notes file with sources, and grounds the TODO.md check proposals in that research. A missing discovery plugin or a halted research call is recorded, and the run continues.
  • Removed. The legacy TODO.md-to-approvals migration: any [x] restart-stopped-service line in TODO.md minted an approval, and the run now writes researched text there.
  • Fixed.
    • Script output is now UTF-8. A console on code page 437 turned "Keeper®" into "Keeperr".
    • The new-finding baseline now keeps an UNKNOWN check that still listed items, as unelevated runs do for startup items and listeners.

Verification

  • Full Pester suite (plugins/machine-health/skills/audit/tests/windows): exit 0.
  • New tests:
    • the candidate selection;
    • the per-check baseline, including the UNKNOWN-with-items and timed-out cases;
    • UTF-8 output, which fails on the old script;
    • removal of the leftover settings file;
    • the step 5 fallback text;
    • a TODO.md [x] line minting no approval.
  • Removed tests covered behavior this PR deletes: the deny settings file, the plugin root pinned into the wrapper, and root quoting for the typed allow rules.
  • Live smoke test: the real wrapper ran claude -p --plugin-dir <worktree> in auto mode against a seeded previous latest.json.
    • Result: ok: true, 15.6 min, permission_denials: [].
    • Notes file: 5 source URLs.
    • Research artifact: written.
    • TODO.md: 3 sourced proposals.
  • Second smoke test after the UTF-8 and baseline fixes: ok: true, 10.2 min, no denials; startup entries researched, "Keeper®" intact in the notes.
  • markdownlint, typos and shell portability: clean.
  • Review fixes: an empty detail.items list now counts as a baseline (Codex P2); the setup text keeps the auto-mode decision and pointer without describing auto mode (Codex P1).

Related

No linked issue. This is Phase 12 of the machine-health PC-checkup plan, after #9067, #9226, #9243 and #9260.

Cost decision (owner, 2026-10-23): at most 5 findings plus 1 proposal pass per monthly run at breadth=low, and a 90-minute wrapper limit.

The plan was reviewed by a fresh-context plan reviewer and a devil's-advocate pass, and the owner approved it on 2026-10-23.

🤖 Generated with Claude Code

kyle-sexton and others added 7 commits October 23, 2026 11:40
Get-ApprovalState reads only state/approvals.json. The one-time migration
that turned checked TODO.md boxes into approvals is gone, with its
-TodoPath parameter, so no TODO.md text can mint an approval. The schema
still accepts an older file's migration block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… path

Invoke-MachineHealthCheck -Scheduled reads the previous latest.json before
overwriting it and writes new_finding_keys, the unmuted FindingKeys under each
check whose previous reading was not UNKNOWN or SKIPPED and did not hold them,
plus discovery_path, <OutputBase>/reports/discovery-<runStamp>.md. The report
names that file under "Newly discovered checks", and the decision page shows
its file name from latest.json. Without -Scheduled neither field is written.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Get-ResearchCandidate.ps1 reads latest.json's new_finding_keys and prints
at most -Max (default 5) candidates of kind startup, task, ext, listener,
process (WARN or CRIT only) or detection, one per kind and title, worst
first, with every other new key listed as not researched. The audit's
research step that consumes it is not wired yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… new findings

The Task Scheduler wrapper is now a static copy that starts
`claude -p ... --permission-mode auto` with a 90-minute limit, so the
scheduled audit can reach the web. The exact allow rules, the deny
settings file and the roots written into the copy are gone; schedule
removes a settings file an earlier build left behind. The Desktop route
offers Auto only.

Under --scheduled the audit uses its normal commands plus -Scheduled,
and step 5 researches up to five new findings through /discovery:research
into a notes file beside the report, grounding its TODO.md proposals with
sources. A missing skill or a halted research call is recorded and the run
continues.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… run

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a console using code page 437, pwsh turned a title such as
"Keeper(R) Password Manager" into "Keeperr", so the model and the
research step saw the wrong text. The three audit scripts the skills run
now set UTF-8 console output, and the monthly wrapper decodes claude's
output as UTF-8 instead of the console code page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…WN check

Unelevated, startup-items and network-listeners read UNKNOWN while still
listing their items, so the severity rule gave them no baseline and new
startup entries and listeners were never researched (seen in a live
scheduled run). A previous entry now counts when it lists detail.items
and is not SKIPPED; one with no items, such as a timed-out check, still
adds nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

PR body contract — issue linkage

This PR body conforms to the issue-linkage contract. Nothing to do.

…s written

The page header now reads "Notes <file>" and hides the label on runs
with no notes file. The report names the notes file only when the state
folder was writable, since research never runs after a state-location
result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton marked this pull request as ready for review October 24, 2026 16:06
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 24, 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-24T16:08:22.841062Z 150124c Draft marked ready
ℹ️ 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 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

claude-security-review: 1 inline finding(s) on 150124c8950fd3f22e523a00f1b819f6253a8ee6; the summary is in this lane's pull request comment.

claude-lane: claude-security-review

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

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

Security review, incremental scope (changes since 150124c): no security issues found.

critical-findings: 0

  • New-RunSnapshot.ps1: the baseline check now tests whether detail.items exists as a property, so a previous check that listed an empty array counts as a baseline. If detail is not a [pscustomobject], the check is skipped from the baseline. Every current item for that check is then treated as new. That errs toward more research candidates, not fewer checks, and Get-ResearchCandidate.ps1 caps candidates at 5. The code handles no new untrusted input and adds no injection, path or privilege surface. It only reads a local previous latest.json.
  • New-RunSnapshot.Tests.ps1: adds a test for the empty-items baseline. This has no security impact.
  • setup/SKILL.md: the text drops the description of auto mode's classifier. It now says the run has no tool list or deny rules of its own, and that auto mode and the owner's settings decide what it may do. This makes the owner-facing disclosure more explicit and removes no instruction or guardrail. The earlier removal of the scheduled deny settings and allow rules is outside this incremental range. It was reviewed at the earlier head.

No plugin manifest (plugin.json or marketplace.json) files are in the incremental change, so no manifest <field> lines apply. No trust-gate paths are touched, so no hold is set.

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

claude-review reviewed 5293803c37c6c897445616fb88bf8f4305d91f13: 0 finding(s), 0 as inline comments.

Incremental review of 5293803, covering New-RunSnapshot.ps1, its Pester test and setup/SKILL.md. I found nothing to flag.

  • Baseline fix (New-RunSnapshot.ps1): Get-NewFindingKey now tests whether the items property exists on detail, instead of testing its value for $null. This fixes the empty-array case. Get-CheckItemKey still reads detail.items the old way, and it wraps the value in @(), so an empty list gives an empty baseline set. The SKIPPED and non-string-id exclusions are unchanged. The -is [pscustomobject] guard fits the previous snapshot, which ConvertFrom-Json produces.
  • New test: the case "keeps the baseline of a check that listed no items" would fail on the old code. With an empty previous list, the old code skipped the check, so the first finding was not reported as new.
  • setup/SKILL.md: the wording now says auto mode and the owner's settings decide what the run may do. That matches the PR description, which says the exact allow rules and the deny settings file were removed. The reference link and the As-of/Recheck markers are kept.

I read the diff and the surrounding helpers only. I did not run the Pester suite. The PR's verification claims are the author's and I did not confirm them. The PR has no closing issue. No plugin manifest changed, and no hold class applies.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 150124c895

ℹ️ 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".

@github-actions github-actions Bot added the needs-human Human-in-the-loop required; autonomous sessions must not resolve items carrying this. label Oct 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

claude-review holds this pull request for a person (cost) at 150124c8950fd3f22e523a00f1b819f6253a8ee6.

The change raises agent spend. plugins/machine-health/skills/setup/templates/monthly-run.ps1 doubles the scheduled claude -p run's -TimeoutSeconds default from 2700 to 5400. plugins/machine-health/skills/audit/SKILL.md step 5 adds one /discovery:research breadth=low model call to every scheduled run, and its Guardrails line lets such a run last up to the wrapper's limit.

claude-lane: claude-review

Reading detail.items through Get-SnapshotField turned an empty array into
$null, so a check with nothing listed last run gave no baseline and its
first finding was never new. Test the property itself. The setup text
keeps the auto-mode decision and pointer without describing how auto mode
works, and states the run has no tool list or deny rules of its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton kyle-sexton removed the needs-human Human-in-the-loop required; autonomous sessions must not resolve items carrying this. label Oct 24, 2026
@kyle-sexton
kyle-sexton added this pull request to the merge queue Oct 24, 2026
Merged via the queue into main with commit c39a5fe Oct 24, 2026
111 of 117 checks passed
@kyle-sexton
kyle-sexton deleted the feat/machine-health-discovery-monthly branch October 24, 2026 18:27
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