feat(routines): rewrite six new routines, ground-truthed and hardened#20
Open
JacobPEvans-personal wants to merge 14 commits into
Open
feat(routines): rewrite six new routines, ground-truthed and hardened#20JacobPEvans-personal wants to merge 14 commits into
JacobPEvans-personal wants to merge 14 commits into
Conversation
New routines: - inspector: daily estate-wide CLAUDE.md/rules/skills violation audit - quartermaster: cross-repo config drift detection and sync - archivist: public docs site and private docs README drift sync - apothecary: dependency/security alert triage and auto-merge pre-labeling - conductor: bot-PR auto-merge (renovate, dependabot, release-please, gh-aw) - distributor: ai-workflows minimum-suite propagation to all repos Custodian trim: - drop pr-triage (Conductor owns it) and aw-health (event-driven GHA will own it) - reduce per-run task count from 2 to 1; rebalance lottery weights Cadence: 14 runs/day (15 on Mondays), one spare slot remaining. Assisted-by: Claude <noreply@anthropic.com>
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
Inspector: trig_01Kaa2rWoVFS4HN4LRR5UMWX Quartermaster: trig_017wzm9n7a8v2yh3tfAsnmg8 Archivist: trig_01U6EPmvAdUDy2k7LfYWkqts Apothecary: trig_015zNd6NJRJZCd784qX5FEgm Conductor: trig_01N7W9LBApg9veyo2NgdprNV Distributor: trig_01HoVTrJjo41JFEyzmY1tU5b Assisted-by: Claude <noreply@anthropic.com>
Every PR and issue created by a cloud routine now carries the same three-layer attribution: title suffix, body Provenance block, and the cloud-routine label. Title suffix: chore(ci): add gh-aw-pin-refresh.yml [routine:distributor] docs(int_homelab): polish README [routine:daily-polish] [routine:custodian] Repo health audit - 2026-05-23 No emoji in titles or bodies (soul rule). Conventional-commit prefix preserved so release-please continues to parse it. Emoji remain in Slack output only, where the rule allows them. Body footer (every PR + every issue): ## Provenance - Generated by: [Routine Name](link) - cron description - Triggered: what fired this run (cron + task lottery if any) - Why this PR/issue: one-line rationale - State: link to state gist - Label: cloud-routine Label: cloud-routine, defined in JacobPEvans/.github/labels.yml in a companion PR. Propagates to every public repo via the existing label-sync.yml workflow - routines do not gh-label-create per repo. PRs are now review-ready, not draft. Draft purgatory blocked the ai-workflows review path (claude-review, final-pr-review, ai-merge-gate) from picking up routine PRs; review-ready opens them to the normal flow. Conductor still does not auto-merge them - its allowlist is bot-author-specific and excludes routine bot identity. Files touched: - routines/daily-polish.prompt.md - drop emoji title, branch becomes docs/daily-polish/<repo>-<date> (was chore/daily-polish, collided across runs). - routines/sentinel.prompt.md - drop emoji title, drop draft. - routines/custodian.prompt.md - repo-audit issue gets [routine:custodian] prefix + Provenance + label. - routines/inspector.prompt.md - drop draft, add suffix/block/label. - routines/quartermaster.prompt.md - same. - routines/archivist.prompt.md - same; private-docs issue too. - routines/distributor.prompt.md - same. - routines/issue-solver.prompt.md - drop emoji prefix from title and from abandon-comment; drop draft. PR title becomes fix(<repo>): <issue title> (#<NNN>) [routine:issue-solver]. - .github/workflows/issue-solver.yml - rename job to 'open a review-ready PR'. - CLAUDE.md - new Attribution conventions section under Hard rules. Future routines inherit the convention. Apothecary, Conductor, Morning Briefing, Weekly Scorecard not touched: they do not create PRs or issues directly. Companion PRs: - JacobPEvans-personal/.github#340 defines the cloud-routine label. - JacobPEvans/ai-workflows attribution PR will follow. Assisted-by: Claude <noreply@anthropic.com>
# Conflicts: # routines/custodian.prompt.md
Per PR #20 §S4: prompts are load-bearing code that the cloud sandbox executes on cron. A malicious or accidental edit to any of these files can mass-mutate the JacobPEvans estate via the JacobPEvans-claude App (contents:write across the owner). Pair with branch protection requiring CODEOWNERS review (separate admin action). Assisted-by: Claude <noreply@anthropic.com>
Adds five new sections to operator guide: 1. Staggered deploy after multi-routine merges (3-stage rollout with 48h watch windows). 2. Hard rules 5-10: paused flag (kill switch via env var), body redaction regex set, Slack output sanitization, state gist schema + per-field retention, shared routine-pr-budget gist, prompt fingerprint logging for drift detection. 3. Review-ready exception for workflow-touching PRs (Inspector no-scripts refactors must be draft). All sections derive from PR #20 reviewer feedback (Claude Opus 4.7, Codex, architecture-critic, cloud-architect, security-auditor, performance-engineer). Companion to the six routine rewrites in the same PR. Assisted-by: Claude <noreply@anthropic.com>
… migration policy Complete rewrite addressing 3 critical reviewer findings plus the correctness gap that prompted PR #20's audit. Architecture changes: - Thin caller YAML (10-15 lines) replaces full-file workflow copies. The reusable workflows in ai-workflows are on: workflow_call; copying them into target repos orphans library code. - uses: refs are 40-char commit SHAs, never tags. Tag resolution cached per run; verification requires web-flow signed commit. - secrets: inherit removed. Tier table declares required secrets per workflow; missing secret in target repo opens an issue, not a broken PR. Tier system: - 4 tiers inline in the prompt (no external suites.yaml — it would have created a cross-repo runtime dependency, day-one no-op risk, and a new injection vector): core (any .github/workflows/*) tests (has tests/ or *_test.* files) nix (flake.nix at root) terraform (any *.tf at root or terragrunt.hcl) - One recursive git/trees call per repo; predicates evaluated as local jq filters (was 246 contents probes per run, now 41). - Opt-out via skip-distributor topic, per-tier opt-out via skip-distributor-<tier>. Migration policy: - Detect already-pollinated repos by Git blob SHA against ai-workflows HEAD + last 3 tagged releases (bounded; ~4 API calls per consumer workflow). - Recognized full-file copies open DRAFT PRs replacing the body with the thin caller. Diverged copies file an issue instead. - Migration cap: 1 PR per repo per run. Excludes: - Workflows: dogfood-*, suite-*, repo-orchestrator, notify-ai-pr (ai-workflows-only), claude-review.yml (deprecated 2026-04-04), all _-prefixed reusables. - Repos: agentics, agent-os (mirrors), tf-static-website (abandoned), splunk-app legacy, profile/meta repos. Cross-cutting controls: - ROUTINE_PAUSED kill switch - Body redaction via CLAUDE.md regex set - Slack output sanitization - Per-repo PR budget consultation (routine-pr-budget gist) - Prompt fingerprint logging - State gist schema v2 with per-field retention (closed_pairs retained indefinitely — rejection memory must outlive trim windows) Reviewer findings addressed: security-auditor S1/S2/S3 (mutable refs, secrets: inherit, signature verification), architecture-critic H1 (over-engineering reduced from 6 tiers to 4), opus-4.7 on suites.yaml wrong layer, codex on migration feasibility (blob-SHA capped, not historical text scan). Assisted-by: Claude <noreply@anthropic.com>
…aching Reduces from 6 rules to 3 retained-with-redesign. Drops the rules that were broken or noise; salvages the two that were dismissed too quickly. Kept (with redesign): - claude-md-staleness — scope expanded to AGENTS.md + SKILL.md. Adds placeholder / glob / URL / absolute-path filters. Output passes through redaction regex (S5) so private paths cannot leak into public PR bodies. Content-hash + resolved-path caches in inspector-state gist (~85-90% read reduction at steady state). - secrets-policy — scoped to src/lib/terraform/ansible/.github/ workflows only. Hard-skips SECURITY.md, README.md, *resume*, obsidian-* repos (the prior version's 100% false-positive rate hit user's own contact emails in personal files). Files an ISSUE in the affected repo — never a PR. Credential expunge is operator judgment (rotate, then expunge from history). - no-scripts — relaxed Inspector's blanket "no workflow PRs" hard rule for this rule only. Safety gates: PRs are DRAFT, post-edit YAML must pass yaml.safe_load, CI must pass before any human review. Refactor extracts run-block to scripts/<name>.sh. Dropped: - soul — folded into Conductor's PR-title regex (Conductor already inspects titles). Scope limited to bot PRs; estate baseline is clean (zero violations in 100-commit sample 2026-05-15..2026-05-25). - tool-use — fuzzy commit-message text matching. Real hits dominated by `cat /api/...` doc references. No actionable fix. - skill-execution-integrity — self-referential. Top hit is the rule's own canonical definition file. Rotation reduced from `% 6` to `% 3`. Cross-cutting controls added: ROUTINE_PAUSED, body redaction, Slack escape, state schema v2 with cache fields, prompt fingerprint. Reviewer findings addressed: security-auditor finding #1 (path leakage — fixed via S5 redaction + skip-list extensions for *.local.md), architecture-critic on premature rule-dropping ("Dropping is cheap. Redesigning is what a staff engineer does."), opus-4.7 on no-scripts salvage path, codex on expanded scope without justification (now justified explicitly). Assisted-by: Claude <noreply@anthropic.com>
… Renovate guard Reduces from 5 drift dimensions to 1, with explicit Renovate-overlap guard so the routine doesn't duplicate Renovate's work in repos that opt into the central preset. Dropped 4 of 5 dimensions (no estate evidence): - osv-ignore-lists: N=2 repos with intentionally disjoint contents - gitignore-patterns: prompt's specific pattern list (.direnv/, .envrc.local, *.pyc) wasn't what was actually in the files - dependabot-schedule: N=1 repo with dependabot.yml - renovate-schedule: schedule lives in JacobPEvans/.github central preset — no local schedule: arrays in any renovate.json Kept: - pre-commit-hooks: real drift confirmed (≥4 distinct major-pin generations of pre-commit-hooks across 15+ repos sampled). New behavior: - Drift threshold: ≥2 minor versions behind upstream latest tag (was: any difference — too noisy). - Renovate-overlap guard: skip if an open Renovate PR targets .pre-commit-config.yaml in the same repo. - Content-hash skip via state gist (cache sha256 of last-scanned config body; re-parse only if changed). - 14-day cooldown per (repo, hook) pair. Cross-cutting controls added: ROUTINE_PAUSED, body redaction, Slack escape, state schema v2, per-repo PR budget, fingerprint. Reviewer findings addressed: architecture-critic on "Quartermaster duplicates Renovate" (now explicitly guarded), opus-4.7 on over-scoping (4-to-1 reduction). Assisted-by: Claude <noreply@anthropic.com>
Drops the prior README↔docs sync premise (impossible — docs.jacobpevans.com is a Mintlify topic-sorted .mdx site with frontmatter and JSX components, not a flat docs/<repo>.md mirror). Routine basename stays archivist; purpose pivots to two tasks rotating daily: Task 1 — readme-quality: - 6-item checklist scoring (exists, purpose paragraph, quickstart, usage/examples, license, length 30-400 lines). - References cited in PR bodies: makeareadme.com, awesome-readme. - Picks lowest-scoring repo, opens 1 review-ready PR addressing the most impactful gap (gap-specific templates for missing-purpose, missing-quickstart, missing-usage, missing-license). - The 7th check originally proposed (broken relative paths) is removed — that's Inspector's claude-md-staleness rule. Avoids cross-routine PR contention on the same files. Task 2 — mintlify-coverage: - Reads docs.json navigation from JacobPEvans/docs. - Cross-references against the non-blacklisted public repo list. - Files ONE issue against JacobPEvans/docs for the most-recently- pushed uncovered repo. Issues only — Mintlify page authoring is editorial (frontmatter, JSX components, narrative prose). - Replaced the prior "diagram with ≥3 repo names" sub-rule (which was silently always-true for common English nouns) with a clean docs.json navigation check. Rotation: % 2 (was: not rotated, single sync task). Dropped: PRIVATE_DOCS_REPO env var path (private docs is a separate concern; out of scope). Cross-cutting controls added: ROUTINE_PAUSED, body redaction, Slack escape, state schema v2, per-repo PR budget, fingerprint. Acknowledged compromise: this is two routines under one name. Follow-up issue (in PR #20 description) commits to revisiting after 30 days of run data; if Task 2 hit rate is low, fold into Morning Briefing. Reviewer findings addressed: architecture-critic H4 (two-routines- in-trench-coat — acknowledged, scheduled revisit), codex on Task 1/ Inspector overlap (check #7 removed), opus-4.7 on issue-only as correct artifact (not PR scaffold), architecture-critic B3 on diagram silently-always-true (replaced with docs.json check). Assisted-by: Claude <noreply@anthropic.com>
…iff-content check Refocuses from "Dependabot triage" to "CodeQL + Dependabot triage" using the correct severity field. Ground-truth data: - Dependabot alerts: zero across 5-repo active sample - CodeQL alerts: present in 3 of 5 sampled repos - Lockfile inventory: only flake.lock and uv.lock exist at root in the estate (8 of 10 prior lockfile patterns were aspirational) - auto-merge-deps label: exists in 2 of 5 sampled repos Changes: - Use rule.security_severity_level (not CVSS — often missing). Dependabot equivalent: security_advisory.severity. - Auto-label gate is now a conjunction of 8 conditions including: state==open, severity==high (Low/Medium do NOT auto-label — that's noise; the prior policy would create label-PR storms on long-standing accepted findings), age >7d, NOT in per-repo codeql_ignore list, file list ⊆ dependency-manifest allowlist (subset, NOT exact-set — Renovate's pyproject.toml + uv.lock pattern would have been rejected by exact-set), diff-content check (every changed hunk line matches a declaration regex — closes the one-byte source-edit bypass), signed commits, auto-merge-deps label provisioned in target repo. - Severity-missing → fail closed (Slack-only, never auto-label). - High/critical alerts → Slack escalation with cooldown (3 days per (repo, alert) pair). - Label-presence gate: skip auto-label and escalate via Slack if auto-merge-deps label missing in target repo. Provisioning is out-of-band via JacobPEvans/.github label-sync (follow-up issue). Cross-cutting controls added: ROUTINE_PAUSED, redaction, Slack escape, state schema v2 (codeql_ignore retained indefinitely), fingerprint. C1 budget doesn't apply — Apothecary opens no PRs. Reviewer findings addressed: security-auditor finding #2 (lockfile bypass — subset + diff-content gate), opus-4.7 on CodeQL severity field (CVSS wrong), opus-4.7 round 2 on exact-set breaking Renovate flows (NOW subset allowlist), architecture-critic on label provisioning (escalate when missing, don't paper-over with inline create). Assisted-by: Claude <noreply@anthropic.com>
…ed-commit verification
Reframes Conductor's value from "auto-merger" to "allowlist enforcement
and cross-repo audit trail" — native gh pr merge --auto --squash plus
branch protection covers ~80% of the merge mechanic. Conductor adds the
gates that native auto-merge doesn't.
Allowlists corrected against 200-PR sample (last 6 months before
2026-05-25):
Author allowlist:
- Kept: renovate[bot], dependabot[bot], github-actions[bot],
jacobpevans-github-actions[bot]
- Dropped (dead entries that never matched): release-please[bot]
(this estate uses github-actions[bot] for release-please),
app/renovate, app/dependabot (App slugs; author.login is
always <name>[bot])
Title-pattern allowlist:
- Added: chore(main): release (44/200 sample — actual release-please
format), fix(deps): (jacobpevans-github-actions action-pin
refreshes), build(deps): / ci(deps): / ci(deps)(deps): (Dependabot)
- Dropped (never matched): chore(release):, chore: release,
chore(gh-aw): refresh action pins
- Added rejection clause: emoji in title (absorbs the prior soul
rule's PR-title concern for bot PRs; scope-note in prompt
documents the estate-wide gap)
New gates (security hardening):
- Release file-allowlist: chore(main): release PRs from
github-actions[bot] must have a changed file set ⊆ {CHANGELOG.md,
manifest, version files, lockfiles} plus per-repo extensions
from conductor-state. Closes the release-please supply-chain
attack where a compromised config could ship arbitrary file
mutations under a release title.
- Signed-commit verification: every commit in the PR must be
web-flow signed (verification.verified == true).
- Minimum PR age: 4 hours (gives humans a review window between
Renovate's instant auto-merge and Conductor's pass).
Workflow-edits exception corrected:
- Was: chore(gh-aw): refresh action pins title (never matched)
- Now: fix(deps): + [aw:gh-aw-pin-refresh] tag + author is
jacobpevans-github-actions[bot]
Blocking-label guard kept as one-line check (none of the labels
are provisioned today; one-line cost survives future label-sync
additions).
Cross-cutting controls added: ROUTINE_PAUSED, Slack escape (PR
titles are user-controlled via package descriptions), state schema
v2 (release_allowlist_extensions indefinite), fingerprint. C1
budget doesn't apply — Conductor merges, doesn't open PRs.
Reviewer findings addressed: security-auditor finding #3
(release-please supply chain — file allowlist + signed commits),
opus-4.7 on framing (allowlist + batching, not the merge mechanic),
opus-4.7 round 2 confirming 4h gate doesn't break Renovate's
auto-merge UX (different paths — Renovate sets native auto-merge
at PR creation; Conductor is the safety-net pass).
Assisted-by: Claude <noreply@anthropic.com>
This was referenced May 25, 2026
Open
…minology) Applies findings from the /simplify pass on the PR #20 rewrites. Efficiency fixes: - apothecary: fetch /pulls/<n>/files once, reuse JSON for Gate 4 (file-list allowlist) and Gate 5 (diff-content check). Eliminates one redundant API call per eligible bot PR. - quartermaster: fetch .pre-commit-config.yaml content and blob SHA in one call instead of two (saves ~one request per repo per run, ~100 calls/run at current estate size). - conductor: replace per-repo gh pr list loop with one org-wide gh search prs call. Saves ~one request per repo per run (~100 calls/run). Per-PR enrichment for mergeability still uses gh pr view because gh search prs doesn't return those fields. Terminology consistency: - Standardize "skip-list" across routines (was a mix of "blacklist", "blacklisted", "skip blacklist"). Inspector already used skip-list; Archivist/Conductor/Apothecary now match. No semantic changes. Lint clean. Assisted-by: Claude <noreply@anthropic.com>
# Conflicts: # routines/issue-solver.prompt.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Update history
1f59d71(refactor(routines): simplify per /simplify review): batched API calls in Apothecary/Quartermaster/Conductor (~200 calls/run saved); unified terminology ("skip-list" everywhere instead of mixed "blacklist"/"skip-list").26f45c4(merge from main): incorporated PR fix(routines): sign Issue Solver commits via createCommitOnBranch GraphQL #19's GraphQLcreateCommitOnBranchsigning fix for Issue Solver; conflict resolution kept both that signing approach AND this branch's "review-ready, not draft" policy (per the unified attribution decision; ai-merge-gate is Issue Solver's human-in-the-loop checkpoint).Rewrites all six new cloud routines (Distributor, Inspector, Quartermaster, Archivist, Apothecary, Conductor) plus the attribution block in
CLAUDE.md. Ground-truthing against the actual JacobPEvans estate revealed broad fabrication in the original PR — invented workflow lists, drift dimensions, docs-site paths, bot allowlists. This rewrite addresses that plus three CRITICAL security flaws and substantial over-engineering surfaced by two rounds of external review (9 reviewers total: Claude Opus 4.7, Codex/gpt-5.2, code-modernization architecture-critic, cloud-architect, security-auditor, performance-engineer, plus a docs.jacobpevans.com fetch and one continuation pass each with Opus and Codex).Full design plan: see
/Users/jevans/.claude/plans/this-whole-pr-needs-peppy-pixel.md(local; planning artifact, not in repo).What this PR contains
Security hardening (critical)
uses:refs in propagated workflow callers are 40-char commit SHAs, never tags. Tag→SHA resolution cached per run; refuses to act unless the resolved commit is web-flow signed. Partial-failure-safe (one workflow's signature failing doesn't abort the whole run).secrets: inheritfrom caller templates. Each tier's required secrets are named explicitly; missing-secret in target repo opens an issue, not a broken PR.chore(main): releasePRs (closes the release-please supply-chain attack where a compromised config could ship arbitrary file mutations under a release title). Plus signed-commit verification on every merge..github/CODEOWNERSrequires@JacobPEvansreview onroutines/**, the deploy skill,CLAUDE.md, andCODEOWNERSitself. Pair with branch protection (separate admin action — follow-up fix: switch deploy trigger from push to workflow_dispatch + daily schedule #4).*.local.md,.envrc*. Provenance "Why" lines describe the rule, never quote the offending string.</>in any field derived from repo content) — closes the<!channel>/<@USER>smuggling attack via package-description-flavored PR titles.Cross-cutting controls (added to
CLAUDE.mdhard-rules 5-10)routine-pr-budgetgist (soft cap 2 PRs per repo per UTC day across all PR-emitting routines). Best-effort; fails open if gist missing.ROUTINE_PAUSEDenv var kill switch.Per-routine rewrites
suites.yamlcross-repo dependency eliminated.claude-md-stalenesswith redaction filter.secrets-policyscoped tosrc/lib/terraform/ansible/workflows, files ISSUES never PRs.no-scriptswith safety gates (draft,yaml.safe_load). Droppedsoul(folded into Conductor),tool-use(fuzzy),skill-execution-integrity(self-referential).docs.jsonnavigation check, issues only). Drops impossible README↔.mdx sync. Acknowledged two-routines-in-one compromise; revisit at 30 days (follow-up harden(custodian): block Write/Edit + move deploy earlier #5).rule.security_severity_level(CVSS unreliable). Subset allowlist + diff-hunk content gate replaces exact-set (which would have broken Renovate's standardpyproject.toml+uv.lockflow). Severity-missing fails closed.chore(main): release,fix(deps):,build(deps):,ci(deps):). File-allowlist for release PRs. Signed-commit verification. 4-hour minimum PR age.Ground-truth data sources (cited in routine prompts)
release-please.ymlat 19/41 (46%).pre-commit-hooksacross 15+ repos sampled.Follow-up issues (filed as part of this PR's merge)
JacobPEvans/.github— Provisionauto-merge-depslabel estate-wide via label-sync (so Apothecary's gate works everywhere).claude-code-routines— Add silent-rot section to Weekly Scorecard.claude-code-routines— Add Sentinel rules for prompt fingerprint drift + state-gist secret scan.claude-code-routines— Enable branch protection on main requiring CODEOWNERS review (admin tier).claude-code-routines— Evaluate Archivist Task 2 (Mintlify coverage) hit rate after 30 days; fold into Morning Briefing if low.Deploy protocol (DO NOT all-at-once)
After merge, deploy via the
.claude/skills/deploy-routine-changes/SKILL.mdskill in this order with 48-hour watch windows between stages:If any stage produces unexpected output, halt and set
ROUTINE_PAUSED=trueon the misbehaving routine via the claude.ai web UI.Backstory commit (Custodian lottery)
The merge from
maininto this branch (commit2de04ab) resolved a conflict inroutines/custodian.prompt.mdbetween the branch's task-trim (droppr-triage+aw-health) and main's task-add (bot-thread-resolvefrom PR #18). Lottery weights rebalanced to sum to 100 across 7 tasks. Already on the branch — no further action needed.Assisted-by: Claude noreply@anthropic.com