Propose RMGR-WP-0020 bounded Forge-sourced freshness runner

Activity Core definition draft (disabled) and activation/rollback plan for
founder review; explicitly not the legacy --all --remote sweep (ADR-002).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 671493@bnt-lap001
Assistant-Session: 60d7b11f-78f9-4731-9367-918511b2762d
This commit is contained in:
tegwick 2026-10-04 12:46:01 +02:00
parent e3940cdc26
commit 29ba3dedcc

View file

@ -0,0 +1,153 @@
---
id: RMGR-WP-0020
type: workplan
title: "Bounded Forge-sourced freshness runner via Activity Core"
domain: infotech
repo: repo-manager
status: proposed
owner: claude-repo-manager
created: "2026-10-04"
updated: "2026-10-04"
flavor: implementation
related: [STATE-WP-0094, STATE-WP-0086, RMGR-WP-0005, RMGR-WP-0017, RMGR-WP-0019]
depends_on: []
---
## Goal
Close the freshness half of STATE-WP-0094-T05 with a supported, bounded and
durable freshness runner. Activity Core schedules it. Repo Manager owns the
engine and selection. State Hub only receives immutable Forge-commit projections.
Evidence of need: `docs/evidence/2026-10-04-freshness-coverage.md`. No C-rule
definition is active; the only one (`state-hub-consistency-sweep`) is paused.
Of 141 active repositories, 35 synced within 24 h, the median age is 109 h and
the maximum is 949 h. Receipts are not durable.
Non-goals and constraints:
- **Not** the legacy `--all --remote` sweep or `POST /consistency/sweep/remote-all`.
ADR-002 forbids central reads or writes of workstation checkouts.
`state-hub-consistency-sweep` stays paused and is retired, not repurposed.
- No full-fleet fan-out per fire, and no `for_each` task spawning (lesson from
daily-sbom-catchup / ACTIVITY-WP-0030).
- No graph-edge receiving. That remains STATE-WP-0094-T05 edge contract work.
- No change in this workplan is enabled, deployed or scheduled without founder authorization (T05).
## Durable freshness receipt contract
```task
id: RMGR-WP-0020-T01
status: todo
priority: high
```
Define `repo-manager.freshness-receipt.v1`. It records the repository, the Forge
commit read via the Forge API or `ls-remote`, the expected/derived commit from the
State Hub `repository-projection-reconcile.v1` receipt, the outcome
(`applied|noop|queued|failed|refused|skipped`), the reason, the runner revision,
the definition id/version, the fire id and UTC timestamps. Choose one durable
read-only-queryable home: the Activity Core run artifact / ops-runs store, or the
Repo Manager evidence sink. Do not use the State Hub DB. This closes the
"last successful / failed receipt" gap.
## Bounded Forge-sourced selector and runner
```task
id: RMGR-WP-0020-T02
status: todo
priority: high
```
Add `rmgr freshness run --limit N --max-seconds S [--dry-run]`:
1. Rank active repositories by the last durable receipt, with never-received
repositories first. Before T01 data exists, fall back to `backing_synced_at`.
2. For each of at most N, resolve the Forge HEAD and skip with `noop` when the last
receipt already matches it.
3. Otherwise reconcile from the immutable Forge commit (STATE-WP-0086 path), never
from a checkout. Verify the receipt the way `projection_sync` does
(primary, instance label, expected == derived == Forge commit).
4. Persist one receipt per repository and stop at `max_seconds`.
`--dry-run` emits the plan only. Tests must cover the ranking, the noop and the
refusals (RMGR-WP-0014/0019 holes stay `refused`, never forced).
## Prepared ActivityDefinition (draft, disabled)
```task
id: RMGR-WP-0020-T03
status: todo
priority: medium
```
Hand the draft below to the activity-core owner as a proposal. Do not edit
activity-core from this repo. It needs a `repo-manager` context source (or the
existing HTTP sink pointed at a Repo Manager endpoint) that calls T02.
```yaml
id: repo-manager-bounded-freshness
name: Repo Manager Bounded Freshness
type: activity-definition
version: "0.1"
enabled: false # founder flips after T05 proof; never in this workplan
owner: repo-manager
governance: custodian
status: proposed
trigger:
type: cron
cron_expression: "40 */2 * * *" # every 2 h, offset from other fleet jobs
timezone: UTC
misfire_policy: skip
context_sources:
- type: repo-manager
query: freshness_run
operation: repo_manager_freshness
required: true
params:
limit: 6 # 141 repos / 6 per fire x 12 fires/day ~= 2-day full rotation
max_seconds: 240
apply: true # declared bounded side-effect; manual runs require confirmation
bind_to: context.freshness
```
Target SLA once enabled: every active, admissible repository has a receipt
younger than 48 h. Non-admissible repositories appear as explicit `refused`
holes.
## Activation and rollback plan (founder review)
```task
id: RMGR-WP-0020-T04
status: wait
priority: high
```
Activation, each step gated:
1. Founder approves T01–T03 design. Deploy the Repo Manager runner image (pinned
digest) and the context source; the definition ships with `enabled: false`.
2. Run two manual fires with `--dry-run`, then two manual fires with `apply`, `limit: 3`.
Verify receipts, zero task spawns and no checkout access.
3. Founder flips `enabled: true`. Re-run `python -m repo_manager.freshness`
after 48 h and accept when the 48 h coverage of admissible repositories is 100 %.
Rollback: set `enabled: false` (or `status: paused`) in the definition ConfigMap
projection and restart nothing else. The runner holds no state beyond receipts,
and projections are idempotent per commit (RMGR-WP-0017), so no data rollback is
needed. To revert the runner itself, redeploy the previous image digest.
Kill criteria: any receipt with an unverified primary, any checkout read, or a
fire that exceeds `max_seconds` twice in a row.
## Proof and handback to State Hub
```task
id: RMGR-WP-0020-T05
status: wait
priority: medium
```
After founder-authorized activation, record bounded freshness evidence:
runner revision, active definition, per-repository Forge commit, last success
and failed/queued receipts, and measured window. Return it to STATE-WP-0094-T05.
Historical registrar holes stay listed until each is resolved.