Skip to content

feat(selfhost): give sweep-watchdog and PR-reconciliation a per-repo opt-out#6319

Merged
JSONbored merged 1 commit into
mainfrom
feat/sweep-watchdog-pr-reconciliation-optout
Jul 16, 2026
Merged

feat(selfhost): give sweep-watchdog and PR-reconciliation a per-repo opt-out#6319
JSONbored merged 1 commit into
mainfrom
feat/sweep-watchdog-pr-reconciliation-optout

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

  • LOOPOVER_SWEEP_WATCHDOG (src/review/sweep-watchdog.ts) and LOOPOVER_PR_RECONCILIATION (src/review/pr-reconciliation.ts) each gate their cron on a global on/off env flag only — there was no way for an operator to exclude a single repo from either scan without flipping the fleet-wide switch.
  • Adds two new force-off-only .loopover.yml fields, review.sweepWatchdog: false and review.prReconciliation: false, wired through packages/loopover-engine/src/focus-manifest.ts exactly like review.selftune (type + parse + present + overlay + serialize), and checked inside each file's existing watchedRepos() loop right after the existing convergence-allowlist/isAgentConfigured watch check.
  • Absent/null/true ⇒ included exactly as today (byte-identical default); only an explicit false excludes the repo. There is no true override — forcing a repo the scan wouldn't otherwise watch into it would bypass the separate convergence-allowlist/acting-autonomy consent boundary, same rationale as selftune's own asymmetric shape.
  • A manifest-load error fails OPEN (the repo stays watched), matching each loop's existing settings-blip fail-safe philosophy — a config-read blip must never silently drop a repo out of monitoring.
  • Part of epic: migrate fleet-wide feature-toggle env vars to .loopover.yml config-as-code #6275 (leaving the epic open for the other fleet-wide toggles still to migrate — not using a closing keyword here).

Scope

  • The PR title follows type(scope): short summary Conventional Commit format, for example fix(api): restore profile access checks.
  • This PR is focused and does not mix unrelated backend, UI, MCP, docs, dependency, and deploy changes.
  • This follows CONTRIBUTING.md and does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked a currently open issue this PR resolves (e.g. Closes #123) — a linked open issue is required for every contributor PR. (N/A — maintainer PR referencing epic epic: migrate fleet-wide feature-toggle env vars to .loopover.yml config-as-code #6275 with "Part of", not a closing keyword, since the epic covers further toggles.)

Validation

  • git diff --check
  • npm run actionlint (via npm run test:ci)
  • npm run typecheck
  • npm run test:coverage locally — 100% line/branch coverage on every changed line in src/review/sweep-watchdog.ts and src/review/pr-reconciliation.ts; packages/loopover-engine/src/focus-manifest.ts's changed lines are also 100%/100% (the file's handful of pre-existing uncovered branches are all in unrelated code this PR never touches).
  • npm run test:workers (via npm run test:ci)
  • npm run build:mcp (via npm run test:ci)
  • npm run test:mcp-pack (via npm run test:ci)
  • npm run ui:openapi:check (via npm run test:ci)
  • npm run ui:lint (via npm run test:ci)
  • npm run ui:typecheck (via npm run test:ci)
  • npm run ui:build (via npm run test:ci)
  • npm audit --audit-level=moderate
  • New or changed behavior has unit/integration tests for new branches, fallback paths, and sanitizer boundaries — added regression tests in test/unit/sweep-watchdog.test.ts and test/unit/pr-reconciliation.test.ts covering: explicit false excludes an otherwise-watched repo, explicit true is a no-op, and a manifest-load error fails open (repo stays watched).

Ran the full local gate via npm run test:ci end-to-end (rebased onto latest main): all test files passed, 0 lint errors, clean typecheck, successful ui:build. npm audit --audit-level=moderate found 0 vulnerabilities.

Safety

  • No secrets, wallet details, hotkeys, coldkeys, user PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics.
  • Auth, cookie, CORS, GitHub App, Cloudflare, or session changes include negative-path tests. (N/A — no auth/session/CORS surface touched.)
  • API/OpenAPI/MCP behavior is updated and tested where needed. (N/A — no API/OpenAPI/MCP surface touched; this is a focus-manifest-only field, same as review.selftune.)
  • UI changes use live API data or real empty/error/loading states, not production mock/demo fallbacks. (N/A — no UI changes.)
  • Visible UI changes include a UI Evidence section below with screenshots. (N/A — no visible UI change.)
  • Public docs/changelogs are updated where needed; changelogs are only edited for release-prep PRs. (.loopover.yml.example and config/examples/loopover.full.yml updated with matching doc blocks for both new fields; CHANGELOG.md untouched.)

UI Evidence

N/A — no visible UI/frontend change.

Notes

  • Both watchedRepos() functions already call resolveRepositorySettings(), which internally loads the repo's focus manifest too (for settings resolution) — this PR's opt-out check loads the manifest a second time via loadRepoFocusManifest(), mirroring selftune-wire.ts's selfTuneRepos(), which does the exact same double-load for the identical reason (no manifest data is threaded back out of resolveRepositorySettings).

…opt-out

Both crons only had a global LOOPOVER_SWEEP_WATCHDOG / LOOPOVER_PR_RECONCILIATION
kill-switch with no repo-level control. Add review.sweepWatchdog and
review.prReconciliation (bool | null, force-off-only, mirroring review.selftune's
established shape) so an operator can exclude one repo from either scan via
.loopover.yml without touching the global flag. A manifest-load error fails open
(the repo stays watched), matching each scan's existing settings-blip fail-safe.
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 16, 2026
@loopover-orb

loopover-orb Bot commented Jul 16, 2026

Copy link
Copy Markdown

Warning

⏸️ LoopOver review result - manual review recommended

Review updated: 2026-07-16 02:19:56 UTC

8 files · 1 AI reviewer · 2 blockers · CI green · clean

⏸️ Suggested Action - Manual Review

Review summary
This PR adds two force-off-only per-repo opt-out fields (review.sweepWatchdog, review.prReconciliation) to .loopover.yml, wiring them through focus-manifest.ts's type/parse/present/overlay/serialize pipeline and checking them in sweep-watchdog.ts/pr-reconciliation.ts's watchedRepos() loops, deliberately mirroring the existing selftune pattern (selftune-wire.ts:selfTuneRepos) field-for-field. The wiring is traceably complete — EMPTY_MANIFEST, emptyManifest, parseReviewConfig, computeReviewConfigPresent, overlayReviewConfig, and reviewConfigToJson are all updated consistently — and the fail-open behavior on manifest-load error is correctly implemented via .catch(() => null) plus a null-safe `manifest?.review.X === false` check, with tests exercising the false/true/error-fallback cases against the real watchedRepos() path. The most notable wrinkle is that the new fields use camelCase (`sweepWatchdog`, `prReconciliation`) while sibling multi-word review.* keys in the same schema use snake_case (`culture_profile`, `finding_categories`, `inline_comments_per_category`), breaking config naming consistency.

Nits — 6 non-blocking
  • focus-manifest.ts: new multi-word keys `sweepWatchdog`/`prReconciliation` are camelCase while every other multi-word `review.*` YAML key in this schema (`impact_map`, `culture_profile`, `finding_categories`, `inline_comments_per_category`) is snake_case — either rename to `sweep_watchdog`/`pr_reconciliation` for consistency or state why these two are the deliberate exception.
  • sweep-watchdog.ts/pr-reconciliation.ts watchedRepos(): loadRepoFocusManifest is now fetched twice per repo per scan (once inside resolveRepositorySettings, once explicitly for the opt-out check) — matches the existing selftune-wire.ts precedent so not a regression, but worth a shared helper/cache if a third cron adopts this pattern.
  • The PR's linked-issue checkbox is unchecked with an inline N/A justification (maintainer PR referencing epic epic: migrate fleet-wide feature-toggle env vars to .loopover.yml config-as-code #6275 via "Part of", not a closing keyword) — flagging per this repo's issue-link requirement rather than silently accepting the justification.
  • Consider snake_case renames `sweep_watchdog`/`pr_reconciliation` in focus-manifest.ts's parseReviewConfig/reviewConfigToJson to match `culture_profile`/`finding_categories` convention, updating the two .yml.example files and the field-exhaustiveness test accordingly.
  • If the double manifest-fetch-per-repo pattern (resolveRepositorySettings + explicit loadRepoFocusManifest) is going to be repeated for more cron passes per epic: migrate fleet-wide feature-toggle env vars to .loopover.yml config-as-code #6275's epic, consider hoisting a single per-repo manifest load that both settings resolution and the opt-out check can share.
  • Readiness score is below the configured threshold — Use the readiness panel as advisory maintainer context; the score does not block this PR.

Concerns raised — review before merging

  • No linked issue detected — If this PR is intended to solve an issue, link it explicitly in the PR body.
  • Maintainer requires a linked issue — Link the relevant issue (for example Closes #123) before opening the PR.
📋 Copy for AI agents — paste into your coding agent
Fix the following blocker(s) from this PR review:

1. No linked issue detected — If this PR is intended to solve an issue, link it explicitly in the PR body.

2. Maintainer requires a linked issue — Link the relevant issue (for example `Closes #123`) before opening the PR.

Decision drivers

  • ❌ Code review — 2 blockers (1 reviewer)
  • ❌ Gate result — Blocking (Repo-configured hard blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ⚠️ Missing No linked issue or no-issue rationale found.
Related work ⚠️ 1 scoped overlap Top overlaps are listed below; lower-confidence bulk is hidden.
Change scope ❌ 8/20 High review scope from cached public metadata (no linked issue context).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 42 registered-repo PR(s), 34 merged, 443 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 42 PR(s), 443 issue(s).
Improvement ✅ Minor risk: clean · value: minor
Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: not available
  • Official Gittensor activity: 42 PR(s), 443 issue(s).
  • Related work: Titles/paths share 8 meaningful terms. (PR #6321)
Contributor next steps
  • Start here: Treat this as maintainer-lane context rather than normal contributor-lane activity.
  • Then work through the remaining 5 steps in the Signals table above.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask <question> answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat <question> answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://gittensory.aethereal.dev/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 16, 2026
@JSONbored
JSONbored merged commit 7ab6071 into main Jul 16, 2026
16 checks passed
@JSONbored
JSONbored deleted the feat/sweep-watchdog-pr-reconciliation-optout branch July 16, 2026 02:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. manual-review Gittensor contributor context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant