Skip to content

Commit 431b1d7

Browse files
committed
fix: add pr264 projection repair contract
1 parent 3dcab74 commit 431b1d7

20 files changed

Lines changed: 2495 additions & 80 deletions

.github/workflows/reviewer-bot-preview.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ on:
1010
required: true
1111
default: preview-check-overdue
1212
type: choice
13-
options: [preview-check-overdue, preview-reviewer-board]
13+
options: [preview-check-overdue, preview-status-label-projection, preview-issue314-state-health, preview-reviewer-board]
1414
issue_number:
1515
description: PR or issue number to preview
1616
required: true
@@ -56,6 +56,11 @@ jobs:
5656
REPO_NAME: ${{ github.event.repository.name }}
5757
GITHUB_REPOSITORY: ${{ github.repository }}
5858
GITHUB_REF: ${{ github.ref }}
59+
EVALUATED_REPO: ${{ github.repository }}
60+
HEAD_SHA: ${{ github.sha }}
61+
EVALUATED_REF: ${{ github.sha }}
62+
GITHUB_RUN_ID: ${{ github.run_id }}
63+
GITHUB_RUN_ATTEMPT: ${{ github.run_attempt }}
5964
WORKFLOW_RUN_ID: ${{ github.run_id }}
6065
WORKFLOW_NAME: ${{ github.workflow }}
6166
WORKFLOW_JOB_NAME: ${{ github.job }}

.github/workflows/reviewer-bot-sweeper-repair.yml

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
name: Reviewer Bot Sweeper Repair
22

3+
run-name: repair ${{ github.event.inputs.action }} issue ${{ github.event.inputs.issue_number }} nonce ${{ github.event.inputs.validation_nonce }}
4+
35
on:
46
schedule:
57
- cron: '0 * * * *'
@@ -10,11 +12,15 @@ on:
1012
required: true
1113
default: check-overdue
1214
type: choice
13-
options: [sync-members, show-state, check-overdue, repair-review-status-labels]
15+
options: [sync-members, show-state, check-overdue, repair-review-status-labels, repair-issue314-state-health]
1416
issue_number:
1517
description: Optional issue or PR number for targeted actions
1618
required: false
1719
type: string
20+
validation_nonce:
21+
description: Validation nonce used to correlate this repair run
22+
required: false
23+
type: string
1824

1925
permissions:
2026
contents: read
@@ -49,14 +55,31 @@ jobs:
4955
EVENT_ACTION: ${{ github.event.action }}
5056
MANUAL_ACTION: ${{ github.event.inputs.action }}
5157
ISSUE_NUMBER: ${{ github.event.inputs.issue_number }}
58+
VALIDATION_NONCE: ${{ github.event.inputs.validation_nonce }}
5259
REPO_OWNER: ${{ github.repository_owner }}
5360
REPO_NAME: ${{ github.event.repository.name }}
5461
GITHUB_REPOSITORY: ${{ github.repository }}
5562
GITHUB_REF: ${{ github.ref }}
63+
EVALUATED_REPO: ${{ github.repository }}
64+
HEAD_SHA: ${{ github.sha }}
65+
EVALUATED_REF: ${{ github.sha }}
66+
GITHUB_RUN_ID: ${{ github.run_id }}
67+
GITHUB_RUN_ATTEMPT: ${{ github.run_attempt }}
5668
WORKFLOW_RUN_ID: ${{ github.run_id }}
5769
WORKFLOW_NAME: ${{ github.workflow }}
5870
WORKFLOW_JOB_NAME: ${{ github.job }}
59-
run: uv run --project "$BOT_SRC_ROOT" reviewer-bot
71+
REPAIR_SUMMARY_PATH: ${{ runner.temp }}/reviewer-bot-repair-output-${{ github.run_id }}-attempt-${{ github.run_attempt }}/repair-summary.json
72+
ISSUE314_STATE_HEALTH_REPAIR_SUMMARY_PATH: ${{ runner.temp }}/reviewer-bot-repair-output-${{ github.run_id }}-attempt-${{ github.run_attempt }}/issue314-state-health-repair-summary.json
73+
run: |
74+
mkdir -p "$RUNNER_TEMP/reviewer-bot-repair-output-${GITHUB_RUN_ID}-attempt-${GITHUB_RUN_ATTEMPT}"
75+
uv run --project "$BOT_SRC_ROOT" reviewer-bot
76+
- name: Upload repair artifact
77+
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808
78+
with:
79+
name: reviewer-bot-repair-output-${{ github.run_id }}-attempt-${{ github.run_attempt }}
80+
path: ${{ runner.temp }}/reviewer-bot-repair-output-${{ github.run_id }}-attempt-${{ github.run_attempt }}
81+
retention-days: 7
82+
if-no-files-found: error
6083
- name: Workflow summary
6184
run: |
6285
{

scripts/reviewer_bot_lib/app.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from dataclasses import dataclass
77

88
from . import maintenance, reconcile
9-
from .context import EventContext, ExecutionResult
9+
from .context import EventContext, ExecutionResult, ManualDispatchRequest
1010
from .event_inputs import build_event_context as decode_event_context
1111
from .maintenance import (
1212
collect_status_projection_repair_items,
@@ -249,7 +249,13 @@ def _classify_event_intent_from_context(bot: AppEventContextRuntime, context: Ev
249249
return bot.EVENT_INTENT_NON_MUTATING_READONLY
250250

251251
if event_name == "workflow_dispatch":
252-
if context.manual_action in {"show-state", "preview-check-overdue", "preview-reviewer-board"}:
252+
if context.manual_action in {
253+
"show-state",
254+
"preview-check-overdue",
255+
"preview-status-label-projection",
256+
"preview-issue314-state-health",
257+
"preview-reviewer-board",
258+
}:
253259
return bot.EVENT_INTENT_NON_MUTATING_READONLY
254260
return bot.EVENT_INTENT_MUTATING
255261

@@ -316,6 +322,7 @@ def execute_run(bot: AppExecutionRuntime, context: EventContext) -> ExecutionRes
316322
workflow_run_result: reconcile.WorkflowRunHandlerResult | None = None
317323
schedule_result: maintenance.ScheduleHandlerResult | None = None
318324
loaded_state_hash: str | None = None
325+
manual_projection_policy: maintenance.ManualDispatchProjectionPolicy | None = None
319326

320327
try:
321328
if (
@@ -352,6 +359,13 @@ def execute_run(bot: AppExecutionRuntime, context: EventContext) -> ExecutionRes
352359
if isinstance(issue_key, str) and issue_key.isdigit()
353360
}
354361
loaded_epoch = state.get("freshness_runtime_epoch") if isinstance(state.get("freshness_runtime_epoch"), str) else None
362+
if event_name == "workflow_dispatch":
363+
manual_projection_policy = maintenance.derive_manual_dispatch_projection_policy(
364+
ManualDispatchRequest(
365+
action=context.manual_action or "",
366+
issue_number=context.issue_number,
367+
)
368+
)
355369

356370
if lock_required:
357371
state, restored = bot.adapters.workflow.process_pass_until_expirations(state)
@@ -442,7 +456,17 @@ def execute_run(bot: AppExecutionRuntime, context: EventContext) -> ExecutionRes
442456
touched_items = schedule_result.touched_items
443457
else:
444458
touched_items = bot.drain_touched_items()
445-
if lock_required and event_name in {"schedule", "workflow_dispatch"} and status_projection_repair_needed(bot, state):
459+
allow_epoch_repair_expansion = (
460+
manual_projection_policy.allow_epoch_repair_expansion
461+
if manual_projection_policy is not None
462+
else True
463+
)
464+
if (
465+
lock_required
466+
and event_name in {"schedule", "workflow_dispatch"}
467+
and allow_epoch_repair_expansion
468+
and status_projection_repair_needed(bot, state)
469+
):
446470
touched_items = sorted(
447471
{
448472
*touched_items,
@@ -542,7 +566,7 @@ def execute_run(bot: AppExecutionRuntime, context: EventContext) -> ExecutionRes
542566
)
543567
_revalidate_epoch(bot, loaded_epoch, "status-label projection")
544568
try:
545-
status_labels_changed = bot.adapters.workflow.sync_status_labels_for_items(state, touched_items)
569+
status_labels_changed = bot.adapters.workflow.sync_status_labels_for_items(state, touched_items)
546570
except RuntimeError as exc:
547571
projection_failure = exc
548572
_log(

scripts/reviewer_bot_lib/config.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,13 @@
122122
STATUS_AWAITING_REVIEWER_RESPONSE_LABEL = "status: awaiting reviewer response"
123123
STATUS_AWAITING_CONTRIBUTOR_RESPONSE_LABEL = "status: awaiting contributor response"
124124
STATUS_AWAITING_WRITE_APPROVAL_LABEL = "status: awaiting write approval"
125+
STATUS_REVIEWER_REASSIGNMENT_NEEDED_LABEL = "status: reviewer reassignment needed"
125126
STATUS_AWAITING_REVIEW_COMPLETION_LABEL = STATUS_AWAITING_REVIEWER_RESPONSE_LABEL
126127
STATUS_LABELS = {
127128
STATUS_AWAITING_REVIEWER_RESPONSE_LABEL,
128129
STATUS_AWAITING_CONTRIBUTOR_RESPONSE_LABEL,
129130
STATUS_AWAITING_WRITE_APPROVAL_LABEL,
131+
STATUS_REVIEWER_REASSIGNMENT_NEEDED_LABEL,
130132
}
131133
STATUS_LABEL_CONFIG = {
132134
STATUS_AWAITING_REVIEWER_RESPONSE_LABEL: {
@@ -141,6 +143,10 @@
141143
"color": "1d76db",
142144
"description": "Assigned review is complete but no visible write+ approval is present",
143145
},
146+
STATUS_REVIEWER_REASSIGNMENT_NEEDED_LABEL: {
147+
"color": "d93f0b",
148+
"description": "Reviewer-bot exhausted the active reviewer cycle and reassignment may be needed",
149+
},
144150
MANDATORY_TRIAGE_APPROVER_LABEL: {
145151
"color": "d73a4a",
146152
"description": "Indicates triage+ approval is required before merge queue",

0 commit comments

Comments
 (0)