ACTIVITY-WP-0044: disabled repo-manager-bounded-freshness draft (RMGR-WP-0020-T03)
Register bounded operation repo_manager_freshness (single attempt, 300 s, code-fixed 'rmgr freshness run --limit N --max-seconds S [--dry-run]') and add the disabled cron definition (40 */2 * * * UTC, limit 6, max_seconds 240). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 692292@bnt-lap001 Assistant-Session: 89c7d8e8-e1b3-47eb-9411-a0ab227fca2f
This commit is contained in:
parent
c6df768ef0
commit
ba4ef00128
9 changed files with 449 additions and 2 deletions
63
src/activity_core/context_resolvers/repo_manager.py
Normal file
63
src/activity_core/context_resolvers/repo_manager.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
"""Repo Manager bounded freshness invocation (RMGR-WP-0020-T03, ACTIVITY-WP-0044).
|
||||
|
||||
Invokes the Repo Manager CLI ``rmgr freshness run --limit N --max-seconds S
|
||||
[--dry-run]`` (RMGR-WP-0020-T02 interface). The argv is code-fixed: a
|
||||
definition supplies only the validated ``limit``, ``max_seconds`` and ``apply``
|
||||
values. The executable is ``rmgr`` on PATH unless the worker sets
|
||||
``ACTIVITY_CORE_RMGR_BIN``; definitions cannot choose it. Stdout is expected to
|
||||
be a JSON object carrying ``receipts`` (``repo-manager.freshness-receipt.v1``);
|
||||
only the counted projection in ``bounded_operations`` is persisted.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
from typing import Any
|
||||
|
||||
# Grace on top of the CLI's own --max-seconds budget for start-up/teardown.
|
||||
_TIMEOUT_GRACE_SECONDS = 30
|
||||
|
||||
|
||||
def build_freshness_argv(params: dict[str, Any]) -> list[str]:
|
||||
limit = int(params["limit"])
|
||||
max_seconds = int(params["max_seconds"])
|
||||
argv = [
|
||||
os.environ.get("ACTIVITY_CORE_RMGR_BIN", "rmgr"),
|
||||
"freshness",
|
||||
"run",
|
||||
"--limit",
|
||||
str(limit),
|
||||
"--max-seconds",
|
||||
str(max_seconds),
|
||||
]
|
||||
if params.get("apply") is not True:
|
||||
argv.append("--dry-run")
|
||||
return argv
|
||||
|
||||
|
||||
def repo_manager_freshness(params: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Run one bounded freshness pass and return its JSON summary."""
|
||||
argv = build_freshness_argv(params)
|
||||
timeout = int(params["max_seconds"]) + _TIMEOUT_GRACE_SECONDS
|
||||
completed = subprocess.run(
|
||||
argv, capture_output=True, text=True, timeout=timeout, check=False
|
||||
)
|
||||
stdout = (completed.stdout or "").strip()
|
||||
if completed.returncode != 0 and not stdout:
|
||||
raise RuntimeError(
|
||||
f"repo_manager_freshness failed (exit {completed.returncode}): "
|
||||
f"{(completed.stderr or '').strip()[:300]}"
|
||||
)
|
||||
try:
|
||||
summary = json.loads(stdout)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise RuntimeError(f"repo_manager_freshness returned invalid JSON: {exc}") from exc
|
||||
if not isinstance(summary, dict):
|
||||
raise RuntimeError("repo_manager_freshness output must be a JSON object")
|
||||
summary.setdefault("apply", params.get("apply") is True)
|
||||
summary.setdefault("limit", int(params["limit"]))
|
||||
summary.setdefault("max_seconds", int(params["max_seconds"]))
|
||||
summary["exit_code"] = completed.returncode
|
||||
return summary
|
||||
Loading…
Add table
Add a link
Reference in a new issue