3 Commits

Author SHA1 Message Date
codex
f8a529e196 feat(hermes): propose fixes for SonarQube findings on a schedule
All checks were successful
Tests / Declarative: Post Actions passed: 1348
Triage has only ever entered on a failure. Static analysis is the opposite
shape - a standing backlog that never fails a build and so never asks anyone
for attention. On this instance that backlog is 139 open findings on Ariadne
alone, each already naming its file, its line, its rule and what is wrong.
That is better-located evidence than the console text the code-repair flow
normally mines, and it was being thrown away.

This is a second way into the same flow, not a second flow. A scheduled sweep
picks one finding and hands it to the existing proposal path, which is
unchanged: Hermes returns a patch as data, Ariadne validates it against the
file it names, pushes a branch, opens a pull request nobody merges. A finding
arriving from outside the build is not a reason to relax the gates that make a
proposal worth reading, so it does not.

Three deliberate limits. Security hotspots are never fetched: SonarQube models
them as needing human review, the quality gate here fails on exactly that
condition, and an automation that resolved them would be marking them
reviewed without review - defeating the control rather than satisfying it.
Findings already marked won't-fix carry a judgement someone made, and
reopening it produces pull requests that argue with a person. And the sweep
proposes one fix per run by default, because 139 pull requests nobody reads
would make the review gate theatre.

Selection is by SonarQube's own effort estimate rather than severity: effort
is the closest available proxy for the one-anchor change the patch validator
can actually check, so a trivial CRITICAL beats an involved MINOR. An
unparseable estimate is treated as ineligible, not as free.

Off by default. Triage reacts to a failure someone already cares about; this
opens pull requests nobody asked for, and that is a decision an operator makes
deliberately rather than inherits on upgrade.

Branch naming now sanitizes its token, since it arrives from a finding key as
well as a build number and a ref is one of the few places where an unexpected
character stops being cosmetic.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 22:08:42 -03:00
codex
d75d4d503e fix(hermes): follow a failing test's imports to the module under test
The bounded patcher could only ever fix defects whose failure output names
the source file. A pytest assertion that fails inside a test names only the
test: on ariadne build 404 the defective file appeared zero times in the whole
174KB console, and candidate selection returned ariadne/app.py, the wrong
file entirely.

Admit test files as readable candidates and follow their absolute imports back
to the module they exercise. Reading widens; writing does not. The patch
validator gates on allowed_path_prefixes alone, so a test file can now be read
for context and still never be patched - which also stops the classic bad fix
of silencing a failing test instead of repairing the code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 01:19:45 -03:00
codex
6da560810f feat(hermes-triage): Gitea issues for escalations, patch proposals for real repos
Two capabilities that make triage useful outside the demo surface.

Issues: when triage concludes a human is needed, file an issue in the
failing service's own repository carrying classification, confidence, the
facts with their sources, the inferences and a Jenkins link, plus a footer
stating Hermes has no write access and nothing was changed. Opt-in per job
via a repo map, deduplicated by job+classification so a repeatedly failing
job yields one issue per kind of failure rather than one per build, and
capped per tick. Disabled by default.

Real-repo patches: candidate files are selected from the console failure
regions (Python, Rust and JS/TS reference patterns), filtered to each
repo's allowed prefixes and suffixes, ranked earliest-failure-first with
source preferred over test files, and fetched whole - never truncated,
because a patch anchor must match exactly. Per-job owner/repo/base-branch
resolution; the patch is validated against the file the model actually
chose, and an unlisted path is rejected.

Legacy single-repo demo behaviour is preserved unchanged.

131 new tests; 472 pass in the hermes suite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 21:04:32 -03:00