Skip to content

feat(selfaudit): add idle-time self-audit sweep + run_self_audit MCP tool - #199

Merged
ytnobody merged 2 commits into
developfrom
hermit/ytnobody/issue-164
Jul 28, 2026
Merged

feat(selfaudit): add idle-time self-audit sweep + run_self_audit MCP tool#199
ytnobody merged 2 commits into
developfrom
hermit/ytnobody/issue-164

Conversation

@ytnobody

Copy link
Copy Markdown
Owner

Summary

Closes #164.

  • Adds a new internal/selfaudit package implementing the lightweight self-audit sweep: dedupe findings against existing GitHub Issues and file (deduped) Issues for real ones.
  • Adds SelfAuditSince to state.LoopState (mirrors RequirementsSweepSince exactly), exposed via the existing get_loop_state/update_loop_state MCP tools.
  • Adds a new run_self_audit MCP tool in internal/mcp/tools.go.
  • Adds github.Client.ListIssuesAnyState (open+closed) since dedup must not re-file an Issue that was already filed and since closed.
  • Extends CLAUDE.md's Superintendent cycle step 9 (rather than renumbering the whole cycle) to run the sweep roughly hourly when the Issue queue is empty.
  • Adds mcp__hermit__run_self_audit to .claude/settings.json's permissions allowlist, and bumps the expected-tool-count assertions in cmd/hermit/serve_test.go (21 → 22).

Go-vs-LLM design rationale (explicit judgment call per the Issue)

run_requirements_sweep and run_health_checks both compute their pass/fail verdict deterministically in Go (a test command's exit code, a health-check command's exit code). "Review the codebase for bugs/missing tests/security holes" has no equivalent deterministic command to shell out to — so that judgment is delegated to the calling LLM (the Superintendent, or an on-demand caller), guided by a single internal/selfaudit.Instructions string that is the one source of truth for what the sweep looks for. CLAUDE.md's step 9 text mirrors this string in prose rather than duplicating the judgment logic.

Everything else — cadence tracking, deduping a finding against existing Issues, and actually filing the Issue — is implemented in Go via internal/selfaudit.File, the single function both the CLAUDE.md-driven idle path and the on-demand run_self_audit MCP tool call. This means the LLM side of the boundary only ever produces structured {title, body} findings and never talks to the GitHub API directly, keeping "Superintendent never fixes, only files Issues" enforced in code rather than relying on prose alone.

run_self_audit is two-phase/stateless between calls:

  1. Called with no findings argument, it returns an instructions field (the shared text above) and files nothing.
  2. Called again with a findings array of {title, body} objects, it dedupes each against existing open and closed Issues (via a new TitlePrefix+normalized-title match, following internal/healthcheck's title-prefix dedup convention but checking ListIssuesAnyState instead of just open issues) and files a new Issue (labeled self-audit) for each non-duplicate.

Dedup is intentionally a simple exact-match-after-normalization heuristic (lowercase, punctuation collapsed, [self-audit] prefix stripped) rather than fuzzy/semantic matching — proportionate to a "lightweight" audit sweep, not a from-scratch duplicate-detection engine.

Test plan

  • go build ./...
  • go vet ./...
  • go test ./... (all packages pass, including new internal/selfaudit tests: cadence-independent File/dedupe logic, GitHubIssueClient adapter, and MCP-tool-level run_self_audit wiring tests)
  • internal/state round-trip test extended to cover SelfAuditSince
  • cmd/hermit tool-count assertions updated for the new tool (21 → 22)

🤖 Generated with Claude Code

…audit tool (Closes #164)

Adds a lightweight, LLM-driven review pass (bugs, missing test coverage,
security holes) that runs when the Superintendent's Issue queue is empty,
throttled to roughly hourly via a new SelfAuditSince cadence timestamp
(mirroring RequirementsSweepSince), plus an on-demand run_self_audit MCP
tool that shares the exact same filing logic.

Design (Go-vs-LLM split, per Issue #164's open judgment call):
- internal/selfaudit is the single implementation both call paths share.
  It cannot itself decide what "a bug" is (unlike run_requirements_sweep's
  test-command exit code, or run_health_checks' check command, there is no
  deterministic verdict to shell out to for "review this code"), so that
  judgment is delegated to the calling LLM via a shared Instructions text.
- Everything mechanical is done in Go: cadence tracking (self_audit_since
  via get_loop_state/update_loop_state, following the existing pattern
  exactly), deduping a finding against BOTH open and closed Issues (a new
  ListIssuesAnyState client method, since a finding whose Issue was
  already filed and since closed must not be re-filed), and actually
  filing the Issue (self-audit label). The Superintendent never touches
  the GitHub API directly for this — it only produces structured findings.
- run_self_audit is two-phase/stateless: called with no `findings` it
  returns instructions to follow; called again with `findings` it dedupes
  and files. This keeps the on-demand and cadence-driven paths identical.

Also updates CLAUDE.md's step 9 (extended rather than renumbering the
whole cycle) to describe the new cadence, the .claude/settings.json
permissions allowlist (new mcp__hermit__run_self_audit entry), and the
expected-tool-count assertions in cmd/hermit/serve_test.go (21 -> 22).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ytnobody

Copy link
Copy Markdown
Owner Author

HERMIT: Superintendentによる補足レビュー(HIGH risk)

evaluate_riskのHIGH判定理由(500行超・.claude/settings.jsonCLAUDE.mdが高リスクパス)を踏まえ、変更内容を確認しました。

変更内容の要約

  • 新規internal/selfauditパッケージ: Finding/Summary/IssueClientと、重複チェック・起票を行うFile()を実装。自動(アイドル時cadence)・オンデマンド(チャットからのMCP呼び出し)の両経路がこの一実装に収束する設計
  • internal/selfaudit/github_adapter.go: 新規github.Client.ListIssuesAnyState(open+closed両方を取得)を使い、[self-audit]プレフィックス付きの正規化タイトル一致で重複判定
  • internal/stateSelfAuditSinceを追加、get_loop_state/update_loop_stateに配線(既存のRequirementsSweepSinceパターンを踏襲)
  • 新規run_self_audit MCPツール: 引数なし呼び出しで監査手順(selfaudit.Instructions)を返し、findings付き呼び出しで重複チェック後にIssue起票(self-auditラベル付与)する二段階方式
  • CLAUDE.md step9を拡張し、Issueキュー空時に約1時間毎でrun_self_auditを呼ぶ手順を追加。「Superintendentは自分で直さない」の原則を明記
  • .claude/settings.jsonrun_health_checksと同じ形で新ツールをallowlistに追加しただけ(内容確認済み、危険性なし)

評価

  • Issue #164の受け入れ条件(コメントで合意した5項目)を満たしている
  • Go側とLLM側の役割分担(監査の「判断」はLLM、重複チェック・起票などの機械的処理はGo側)がパッケージdocコメントに明記されており、設計判断の根拠が追跡可能
  • 「Superintendentは実装しない」という境界が、ツール自体がコード編集手段を一切持たない(Issue起票のみ)という構造で担保されている点が良い
  • 重複判定はopen/closed両方を見るため、一度起票してcloseされた指摘が再度起票されない設計になっている(受け入れ条件通り)
  • テストは新パッケージ本体・アダプタ・MCPツール配線のいずれもカバーしており、重複ケース・エラー伝播ケースも含む
  • CI(Lint/Test/Security Scan)全てpassing、mergeable: MERGEABLE/CLEAN

懸念点は見当たりません。 HIGH riskは変更量とパスの機微性によるフラグであり、実装内容としては安全にマージ可能と判断します。マージはポリシー通り人間の判断待ちとします。

@ytnobody

Copy link
Copy Markdown
Owner Author

⚠️ HERMIT: HIGH risk detected.
Reasons: [500 or more lines changed .claude/settings.json is in a high-risk path CLAUDE.md is in a high-risk path]

…sue-164

# Conflicts:
#	internal/mcp/tools.go
@ytnobody
ytnobody merged commit 60b9a38 into develop Jul 28, 2026
3 checks passed
@ytnobody
ytnobody deleted the hermit/ytnobody/issue-164 branch July 28, 2026 08:29
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.

アイドル時のセルフ監査(bug/テスト不足/セキュリティホール検知)+ オンデマンドMCPツール追加

1 participant