GitNexus/.github/workflows
Gergő Magyar becac9a5d3
feat(eval): run the skill-evolution loop online (#2571)
* feat(eval): run the skill-evolution loop online

Add a scheduled + dispatch-gated workflow that runs the offline
propose -> benchmark -> gate loop (workflow_bench.evolve) in CI with the
pinned Claude canary runtime and bubblewrap containment, uploads the
benchmark evidence as an artifact, and on a gate-passed promotion opens
a human-reviewed PR via the release App token. The applied overlay is
bounded to the canonical skill tree and its shipped mirrors; any escape
fails the run instead of reaching a PR.

The scheduled lane ships disabled behind GITNEXUS_EVOLUTION_ENABLED and
requires the new GITNEXUS_BENCH_AUTH_TOKEN secret (benchmark sessions
bill real API usage), mirroring the review agent's staged rollout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Va5uu9Ar3e45QZ5xFsG4AZ

* fix(ci): restructure promotion-PR script so no lint suppression is needed

Replace the inline single-quoted credential helper with a GIT_ASKPASS
file written via a quoted heredoc (the App token still reaches git only
through step env at push time), and assemble the PR body from quoted
heredocs plus double-quoted printf instead of a backtick-laden
single-quoted template. Every run script in the workflow now passes
shellcheck with zero findings and zero disables; the body and askpass
rendering are smoke-tested.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Va5uu9Ar3e45QZ5xFsG4AZ

* fix(ci): apply gate-passing overlays in the evolution loop

The loop invoked workflow_bench.evolve without --apply, so
apply_promoted_overlay (its only working-tree writer, gated by
`if args.apply:`) never ran. git status stayed clean, promoted=false was
emitted every run, and the App-token/PR-open steps were unreachable dead
code — a gate-passing run went green as "No promotion this run".

validate_promotion_for_apply already runs before the apply gate, so
adding --apply lets a passing candidate reach the tree without weakening
the deterministic gate; the boundary check then confirms it stayed in the
skill trees.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Va5uu9Ar3e45QZ5xFsG4AZ

* fix(ci): provision ~/GitNexus so the benchmark repo resolves on CI

Every scenario in tasks.scenarios.yaml addresses the target repo as
~/GitNexus; runner_tasks.py resolves it with expanduser().resolve() then
`git -C <repo> rev-parse`, which raises when the path is missing. On a
hosted runner the checkout lands in $GITHUB_WORKSPACE and nothing created
~/GitNexus, so the first real run failed at task-binding.

Symlink ~/GitNexus -> $GITHUB_WORKSPACE before the loop. The checkout uses
fetch-depth: 0 (full history for the parentless clone), and the benchmark
only clones the repo copy-on-write and mounts deps read-only, so the
checkout is never mutated. GITNEXUS_BENCH_ORACLE_ROOT stays unset — it
defaults to the in-repo oracles dir and is staged by the harness.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Va5uu9Ar3e45QZ5xFsG4AZ

* fix(ci): harden promotion summary output and PR branch recovery

Three fixes to the promotion-detection and PR-open steps:

- GITHUB_OUTPUT summary used a fixed `PROMOTION_EOF` heredoc delimiter; a
  value containing that marker on its own line could close the block early
  and inject output keys. Use a per-run random delimiter, matching the
  pattern already in tree-sitter-upgrade-readiness.yml.
- The summary concatenated every generation's promotion.json (including
  rejected ones), so the PR body could show a losing generation's
  decisions. The loop returns on the first promotion, so emit only the
  highest-numbered gen-N/bench/promotion.json — the decision that fired.
- The promotion branch name omitted the run attempt. GITHUB_RUN_ID is
  stable across re-runs, so a re-run after push-succeeds/PR-create-fails
  could never push. Include ${GITHUB_RUN_ATTEMPT} (the artifact name
  already does).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Va5uu9Ar3e45QZ5xFsG4AZ

* fix(ci): least-privilege the promotion App token and gate on an Environment

The Mint-App-Token step passed only app-id + private-key, so the minted
token inherited every permission the Release App installation holds
(including Workflows: write) — far more than "push a branch, open a PR".
Switch to `client-id` (as publish.yml does) and request only
permission-contents: write + permission-pull-requests: write.

Bind the job to a protected Environment (gitnexus-evolution) so promotion
runs can be gated server-side. workflow_dispatch runs the workflow and
in-tree evolve.py from the *dispatched ref*, so a code-side ref guard is
removable by the dispatched branch itself; an Environment deployment-branch
rule (main only) is the boundary that holds. The admin steps to create it
and scope the secrets are documented in the activation checklist.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Va5uu9Ar3e45QZ5xFsG4AZ

* fix(ci): correct upload-artifact pin comment and add shell strict-mode

- The upload-artifact SHA 043fb46d… is v7.0.1 (labeled so in the sibling
  workflows that pin it); the comment mislabeled it # v6.0.0. Correct the
  comment; the pin is unchanged.
- Add `set -euo pipefail` to the two build steps that lacked it, matching
  every other run block in the file (GitHub's default shell already sets
  -eo pipefail; this adds -u and consistency).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Va5uu9Ar3e45QZ5xFsG4AZ

* docs(ci): complete the skill-evolution activation checklist

- Add RELEASE_APP_ID / RELEASE_APP_PRIVATE_KEY to the required-secrets
  checklist (the Mint step hard-fails without them on a promotion) and the
  App-install-scope verification.
- Document the protected Environment admin step and why it is the real
  boundary for the workflow_dispatch ref-secret exposure.
- Note that workflow_dispatch runs the billing loop regardless of
  GITNEXUS_EVOLUTION_ENABLED.
- Justify the weekly cron against the README's ~90-day guidance and note the
  355-minute timeout ceiling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Va5uu9Ar3e45QZ5xFsG4AZ

* fix(eval): redact API tokens from diagnostic fields before artifact upload

results.jsonl (runner.py) and proposer-session.json (evolve.py) serialize
session records whose error_detail can carry a stderr_tail that echoed the
API key. Transcripts are redacted before persistence, but these two sinks
were not, and both land in the 14-day evolution artifact.

Run each record's serialized JSON through the existing redact_text with the
run's auth token before writing. Scoped to these diagnostic sinks only: the
promoted overlay and proposal.md are left untouched (the overlay is the
applied artifact and must stay byte-identical for apply and the
shipped-skills-sync guard).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Va5uu9Ar3e45QZ5xFsG4AZ

* test(ci): add a contract test for the skill-evolution workflow

No test exercised this workflow's path, which is why both P1 blockers
(missing --apply, unresolvable ~/GitNexus task repo) reached production.
Parse the workflow YAML and assert the structural contract: --apply is
passed, the task repo is provisioned, the promotion branch carries the run
attempt, the App token is permission-scoped and the job is Environment-
gated, the output summary uses a random delimiter and a single generation,
the artifact pin is labelled correctly, and every multi-line shell step
sets strict mode. Follows the review-agent-workflow.test.ts precedent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Va5uu9Ar3e45QZ5xFsG4AZ

* feat(ci): run the proposer on its own (stronger) model

One `model` input drove both the benchmark arms and the proposer/diagnosis
session. Split them: `model` stays the benchmark arms (match the model your
skill users run, so a promotion is valid for them and the tasks aren't
ceiling-saturated), and a new `proposer_model` input runs the proposer —
the harder meta-reasoning task that writes the candidate skill, and only one
session per generation, so a stronger model is cheap here. evolve.py already
supports --proposer-model; the workflow just didn't expose it.

Defaults: arms = claude-sonnet-5, proposer = claude-opus-4-8 (both
overridable via workflow_dispatch). The weekly cadence bounds the added
spend. Contract test asserts the split stays wired.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Va5uu9Ar3e45QZ5xFsG4AZ

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 05:37:07 +01:00
..
build-tree-sitter-prebuilds.yml chore(deps): bump actions/attest-build-provenance from 4.1.0 to 4.1.1 (#2406) 2026-07-09 06:51:04 +01:00
ci-devcontainer.yml chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 (#2292) 2026-06-25 06:53:47 +01:00
ci-e2e.yml chore(deps): bump dorny/paths-filter from 4.0.1 to 4.0.2 (#2505) 2026-07-16 07:02:56 +01:00
ci-quality.yml chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 (#2292) 2026-06-25 06:53:47 +01:00
ci-report.yml chore(deps): bump marocchino/sticky-pull-request-comment (#2537) 2026-07-17 13:20:48 +01:00
ci-tests.yml feat(skills): GitNexus Engineering Tool Kits (#2566) 2026-07-19 15:07:24 +01:00
ci.yml refactor(ingestion): delete legacy call-resolution DAG + heritage processor (RING4-1, #942) (#2023) 2026-06-04 11:07:37 +01:00
claude.yml chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 (#2292) 2026-06-25 06:53:47 +01:00
codeql.yml chore(deps): bump github/codeql-action/analyze from 4.36.2 to 4.37.0 (#2506) 2026-07-17 11:40:51 +01:00
commit-fork-prebuilds.yml chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 (#2292) 2026-06-25 06:53:47 +01:00
dependency-review.yml chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 (#2292) 2026-06-25 06:53:47 +01:00
docker.yml chore(deps): bump docker/metadata-action from 6.1.0 to 6.2.0 (#2536) 2026-07-17 13:21:05 +01:00
gitleaks.yml chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 (#2292) 2026-06-25 06:53:47 +01:00
gitnexus-review-agent.yml feat(ci): review agent on Sonnet 5 with structured, linked reviews (#2570) 2026-07-19 17:45:35 +01:00
gitnexus-skill-evolution.yml feat(eval): run the skill-evolution loop online (#2571) 2026-07-20 05:37:07 +01:00
grammar-update-monitor.yml chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 (#2292) 2026-06-25 06:53:47 +01:00
impact-pdg-mutation-report.yml chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 (#2292) 2026-06-25 06:53:47 +01:00
pr-autofix-apply.yml chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 (#2292) 2026-06-25 06:53:47 +01:00
pr-autofix-publish.yml feat(autofix): replace inline reviewdog with /autofix ChatOps button (#1458) 2026-05-09 16:32:38 +01:00
pr-autofix.yml chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 (#2292) 2026-06-25 06:53:47 +01:00
pr-description-check.yml chore(deps): bump actions/github-script from 7.0.1 to 9.0.0 2026-04-15 20:17:08 +00:00
pr-labeler.yml chore(deps): bump release-drafter/release-drafter from 7.4.0 to 7.5.1 (#2398) 2026-07-09 06:48:55 +01:00
publish.yml feat(skills): GitNexus Engineering Tool Kits (#2566) 2026-07-19 15:07:24 +01:00
scorecard.yml chore(deps): bump github/codeql-action/upload-sarif (#2535) 2026-07-17 13:21:25 +01:00
skill-sync.yml feat(skills): GitNexus Engineering Tool Kits (#2566) 2026-07-19 15:07:24 +01:00
tree-sitter-upgrade-readiness.yml chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 (#2292) 2026-06-25 06:53:47 +01:00
triage-sweep.yml chore(deps): bump actions/cache from 5.0.5 to 6.1.0 (#2351) 2026-07-02 07:11:57 +01:00
trivy.yml chore(deps): bump github/codeql-action/upload-sarif (#2535) 2026-07-17 13:21:25 +01:00
workflow-lint.yml chore(deps): bump github/codeql-action/upload-sarif (#2535) 2026-07-17 13:21:25 +01:00