Files
cleveragents-core/tools/controller/master/__init__.py
T
drew 3e269ce011 feat(controller): Phase 1j — deterministic CI summarizer + priority parsers
Replaces "ci_summary=None / failing_gates=[]" placeholders from Phase
1h with a real summarizer that maps Forgejo combined-status →
CISummary V1 dict by running per-tool deterministic parsers on each
failing gate's log.

Priority parsers shipped (cover lint/format/typecheck/unit_tests, the
4 most-failed gates):
- ruff      — F+E codes from `nox -s lint`; Would-reformat lines from
              `nox -s format`. Aggregates to single error_class when
              all findings share one code, else RuffMixed.
- pyright   — error/warning/information diagnostics; rule name pulled
              from trailing `(reportName)` parens. Abs-path
              normalization strips container prefixes.
- behave    — failing scenarios (file:line + name), AssertionError
              extraction. Feature/scenario summary line aggregation.

Stub parsers for not-yet-shipped tools (robot_framework, slipcover,
bandit, semgrep, vulture, radon, build): return a structured
CIFailure with error_class="parser-pending-{name}" + the raw log
excerpt. Operators see the failure; implementer still has log
context. Phase 1j+ replaces stubs with real parsers without changing
the gate-→-session map.

Components:
- _base.py        — ParserResult dataclass + select_log_excerpt()
                    (tail-N-lines smart selection within 16KB cap)
- _stub.py        — make_stub(name) factory for pending tools
- _registry.py    — resolve(parser_name) + resolve_for_nox_session()
                    + validate_parser_coverage()
- master/ci_summarize.py — summarize_ci_status(head_sha, status,
                    log_fetcher) orchestrator. Handles:
                    - composite multi: gates → CIFailure.composite_findings
                    - log_fetcher returning None → log-fetch-failed
                    - log_fetcher raising → caught + log-fetch-failed
                    - Unknown gate context → NoParserAvailable
                    - Forgejo state=None → unknown summary
                    - Parameterized matrix gates ("unit_tests-3.13")
                      → base session name resolution

Tests (+46 across 2 new files, 0 regressions):
- Per-parser canonical + empty + garbage input
- Registry resolution (real vs stub), coverage validator
- Summarizer V1 contract round-trip
- Composite security_scan composite_findings shape
- Error paths (None status, raising fetcher, unknown gate)
- Parser version aggregation across mixed gates

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 14:40:16 -04:00

177 lines
4.4 KiB
Python

"""Master controller — singleton orchestrator.
Per plan v9: the master process is a singleton per (owner, repo). It:
1. Runs discovery (Forgejo poll) — Phase 1d-3
2. Drives the state machine: for each non-terminal workflow, advance
one step based on the outcome of its latest completed attempt
3. Runs the reaper + pickup guard each tick
4. Performs Forgejo writes (status comments, labels, merges) —
Phase 1d-3+
5. Runs periodic reconciliation (DB↔Forgejo) — Phase 1d-3+
This package ships incrementally. Phase 1d-1 (already shipped) had
the state machine + reaper + pickup guard. This Phase 1d-2 adds:
- ``outcomes.py``: maps worker output_payload outcomes → state machine
events (e.g., implementer outcome='resolved''implementer_pushed';
outcome='rebase-failed''implementer_rebase_failed').
- ``tick.py``: one tick handler — scans recently-completed attempts,
applies events to their workflows, emits controller_events.
"""
from .outcomes import (
EventMapResult,
map_outcome_to_event,
)
from .tick import (
TickReport,
run_tick,
)
from .scheduler import (
MAX_TIER,
PrefetchCallback,
ScheduledAttempt,
SchedulerReport,
schedule_next_attempts,
)
from .discovery import (
DiscoveredEntity,
DiscoveryReport,
ListIssuesCallback,
ListPRsCallback,
run_discovery,
)
from .forgejo_writes import (
AddLabelCallback,
GetLabelsCallback,
LabelAdjustResult,
ListCommentsCallback,
PostCommentCallback,
RemoveLabelCallback,
StatusCommentResult,
adjust_labels,
build_marker,
comment_has_fingerprint,
compute_fingerprint,
post_status_comment,
)
from .merging import (
MAX_BACKOFF_S,
MAX_MERGE_RETRIES,
MergeCallback,
MergeResponse,
MergingHandlerReport,
run_merging_tick,
)
from .forgejo_http import (
ForgejoCallbacks,
build_callbacks,
)
from .backfill import (
BACKFILL_MARKER_EVENT_TYPE,
BackfillReport,
has_backfill_run,
run_startup_backfill,
)
from .ci_summarize import (
LogFetcher,
summarize_ci_status,
)
from .prefetch import (
GetPRDetailsCallback,
GetPRDiffCallback,
ListPRCommentsCallback,
ListPRReviewsCallback,
PrefetchDataCallbacks,
build_conflict_resolver_input,
build_estimator_input,
build_implementer_input,
build_reviewer_input,
make_prefetch_callback,
)
from .reconciliation import (
GetIssueStateCallback,
GetPRStateCallback,
ReconciliationAction,
ReconciliationReport,
run_reconciliation_tick,
)
from .loop import (
MasterConfig,
MasterTickReport,
master_main_loop,
run_master_iteration,
)
__all__ = [
# Discovery
"DiscoveredEntity",
"DiscoveryReport",
"ListIssuesCallback",
"ListPRsCallback",
"run_discovery",
# Outcome mapping
"EventMapResult",
"map_outcome_to_event",
# Scheduler
"MAX_TIER",
"PrefetchCallback",
"ScheduledAttempt",
"SchedulerReport",
"schedule_next_attempts",
# Tick
"TickReport",
"run_tick",
# Main loop
"MasterConfig",
"MasterTickReport",
"master_main_loop",
"run_master_iteration",
# Forgejo writes
"AddLabelCallback",
"GetLabelsCallback",
"LabelAdjustResult",
"ListCommentsCallback",
"PostCommentCallback",
"RemoveLabelCallback",
"StatusCommentResult",
"adjust_labels",
"build_marker",
"comment_has_fingerprint",
"compute_fingerprint",
"post_status_comment",
# MERGING handler
"MAX_BACKOFF_S",
"MAX_MERGE_RETRIES",
"MergeCallback",
"MergeResponse",
"MergingHandlerReport",
"run_merging_tick",
# HTTP adapter (Forgejo wiring)
"ForgejoCallbacks",
"build_callbacks",
# Backfill (master startup)
"BACKFILL_MARKER_EVENT_TYPE",
"BackfillReport",
"has_backfill_run",
"run_startup_backfill",
# Reconciliation (periodic DB ↔ Forgejo sync)
"GetIssueStateCallback",
"GetPRStateCallback",
"ReconciliationAction",
"ReconciliationReport",
"run_reconciliation_tick",
# Prefetch (Phase 1h)
"GetPRDetailsCallback",
"GetPRDiffCallback",
"ListPRCommentsCallback",
"ListPRReviewsCallback",
"PrefetchDataCallbacks",
"build_conflict_resolver_input",
"build_estimator_input",
"build_implementer_input",
"build_reviewer_input",
"make_prefetch_callback",
# CI summarizer (Phase 1j)
"LogFetcher",
"summarize_ci_status",
]