Generic provider-agnostic PR/issue watcher service (pr-watch@<instance>) [epic #796] #801

Open
opened 2026-07-16 20:21:59 +00:00 by jason.woltje · 0 comments
Owner

Parent epic: #796 (Agent Roster + webUI oversight + health watch family). Design-first — this issue tracks design before implementation; implementation slots AFTER the current MS delivery queue (M5-001 pivot > #790 > #791 > #792) unless reprioritized. Origin: Jason (Discord 2026-07-16 20:20Z) via Mos.

Goal

Codify the ad-hoc PR-watch capability as a generic, provider-agnostic PR/issue watcher service — configurable and deployable against any git-based forge (GitHub, Gitea, GitLab, Forgejo, …), running as pure code with NO agentic intervention, bound to repos at a 1:1 service:repo ratio. The natural shape is a systemd template unit pr-watch@<instance> (one instance per watched repo).

Why (cautionary spec)

The existing jarvis-brain infra/fleet-enhance-nightly gitea_pr_watch.py ran a silent crash-loop for ~4 weeks unnoticed (the gitea-pr-watch blackhole). The generic service therefore MUST be health-watch-integrated / self-announcing from day one — a dead instance must surface via the fleet health watch (enhance Tier-2 watch-the-watchers), never fail silent.

Prior art to mine (do NOT reinvent)

  • (a) gitea_pr_watch.py (jarvis-brain infra/fleet-enhance-nightly) incl. today's #65 fix + the pending P0 broaden-except ((subprocess.CalledProcessError, OSError) so a missing tmux binary can't reopen the poison-loop). Its 4-week silent failure = the cautionary spec above.
  • (b) prwatch0 agent-session notify semantics = the behavioral spec to REPLACE with code: head-move, mergeable-flip, terminal-pipeline events (CI reaching a terminal state). These are the events the service emits.
  • (c) enhance's R0 deploy-clone model (never exec from dev checkouts) + Tier-2 watch-the-watchers = the service's deployment + monitoring home.

Design decisions (to resolve in the design doc)

  1. Provider abstraction — a thin provider interface (list open PRs/issues, PR head sha, mergeable state, CI/pipeline status) with adapters per forge (GitHub/Gitea/GitLab/Forgejo). One behavioral contract, N adapters.
  2. Webhook vs poll — per-instance choice (webhook where the forge supports it + is reachable; poll fallback). Document the trade-off and the default.
  3. Per-instance credential handling — via the existing credential loader (~/.config/mosaic/tools/_lib/credentials.sh / load_credentials); never inline secrets; no secret value in any output/log.
  4. Instance configpr-watch@<instance> resolves an instance config (forge kind, repo, endpoint, credential key, event set, webhook|poll, interval). Deploy-clone model (not dev checkout).
  5. Event emission + notify — head-move / mergeable-flip / terminal-pipeline; C1-safe notify (stdin load-buffer -, notify failure returns status and never aborts the state write — no poison-loop), state-file dedup.
  6. Health-watch integration — register each instance so enhance Tier-2 flags a FAILED pr-watch@<instance> unit within one sweep (self-announcing).

Coordination / overlaps

  • Belongs in the #796 epic family design phase (planner-opus leased). It consumes the same fleet-health substrate: enhance owns the headless watch-the-watchers collector; a dead pr-watch@<instance> is one of the failures it must surface. Align the service's health signal with enhance's latest.json contract.
  • The P0 broaden-except micro-fix on the CURRENT gitea_pr_watch.py is enhance's decoupled fast-follow (not this issue) — but this generic service must carry the same OSError-safe notify from the start.

Firewall

Operator-agnostic → mosaicstack/stack proper (per the framework firewall). No SOUL/USER/operator specifics in the service; instance configs + credentials are operator data supplied at deploy, not shipped.

Acceptance (design phase)

A design doc under docs/design/ (provider abstraction, webhook-vs-poll, credential handling, instance/unit model, event semantics, health-watch integration, test plan). Standard MS gates on any subsequent implementation (TDD ≥85%, independent review, secrev on the credential surface, trunk-based squash PR, merge + descendant-green + issue close).

**Parent epic:** #796 (Agent Roster + webUI oversight + health watch family). **Design-first** — this issue tracks design before implementation; implementation slots AFTER the current MS delivery queue (M5-001 pivot > #790 > #791 > #792) unless reprioritized. Origin: Jason (Discord 2026-07-16 20:20Z) via Mos. ## Goal Codify the ad-hoc PR-watch capability as a generic, **provider-agnostic** PR/issue watcher **service** — configurable and deployable against any git-based forge (GitHub, Gitea, GitLab, Forgejo, …), running as **pure code with NO agentic intervention**, bound to repos at a **1:1 service:repo ratio**. The natural shape is a **systemd template unit `pr-watch@<instance>`** (one instance per watched repo). ## Why (cautionary spec) The existing `jarvis-brain infra/fleet-enhance-nightly gitea_pr_watch.py` ran a **silent crash-loop for ~4 weeks** unnoticed (the gitea-pr-watch blackhole). The generic service therefore MUST be **health-watch-integrated / self-announcing from day one** — a dead instance must surface via the fleet health watch (enhance Tier-2 watch-the-watchers), never fail silent. ## Prior art to mine (do NOT reinvent) - **(a) `gitea_pr_watch.py`** (jarvis-brain infra/fleet-enhance-nightly) incl. today's **#65 fix** + the **pending P0 broaden-except** (`(subprocess.CalledProcessError, OSError)` so a missing `tmux` binary can't reopen the poison-loop). Its 4-week silent failure = the cautionary spec above. - **(b) `prwatch0` agent-session notify semantics** = the behavioral spec to REPLACE with code: **head-move**, **mergeable-flip**, **terminal-pipeline events** (CI reaching a terminal state). These are the events the service emits. - **(c) enhance's R0 deploy-clone model** (never exec from dev checkouts) + **Tier-2 watch-the-watchers** = the service's deployment + monitoring home. ## Design decisions (to resolve in the design doc) 1. **Provider abstraction** — a thin provider interface (list open PRs/issues, PR head sha, mergeable state, CI/pipeline status) with adapters per forge (GitHub/Gitea/GitLab/Forgejo). One behavioral contract, N adapters. 2. **Webhook vs poll** — per-instance choice (webhook where the forge supports it + is reachable; poll fallback). Document the trade-off and the default. 3. **Per-instance credential handling** — via the existing credential loader (`~/.config/mosaic/tools/_lib/credentials.sh` / `load_credentials`); **never inline secrets**; no secret value in any output/log. 4. **Instance config** — `pr-watch@<instance>` resolves an instance config (forge kind, repo, endpoint, credential key, event set, webhook|poll, interval). Deploy-clone model (not dev checkout). 5. **Event emission + notify** — head-move / mergeable-flip / terminal-pipeline; C1-safe notify (stdin `load-buffer -`, notify failure returns status and never aborts the state write — no poison-loop), state-file dedup. 6. **Health-watch integration** — register each instance so enhance Tier-2 flags a FAILED `pr-watch@<instance>` unit within one sweep (self-announcing). ## Coordination / overlaps - Belongs in the **#796 epic family** design phase (planner-opus leased). It consumes the same fleet-health substrate: enhance owns the headless watch-the-watchers collector; a dead `pr-watch@<instance>` is one of the failures it must surface. Align the service's health signal with enhance's `latest.json` contract. - The **P0 broaden-except** micro-fix on the CURRENT `gitea_pr_watch.py` is enhance's decoupled fast-follow (not this issue) — but this generic service must carry the same OSError-safe notify from the start. ## Firewall Operator-agnostic → **mosaicstack/stack proper** (per the framework firewall). No SOUL/USER/operator specifics in the service; instance configs + credentials are operator data supplied at deploy, not shipped. ## Acceptance (design phase) A design doc under `docs/design/` (provider abstraction, webhook-vs-poll, credential handling, instance/unit model, event semantics, health-watch integration, test plan). Standard MS gates on any subsequent implementation (TDD ≥85%, independent review, secrev on the credential surface, trunk-based squash PR, merge + descendant-green + issue close).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#801