From 304988a7fcbb1b51119aa576f58aa73c40b96eda Mon Sep 17 00:00:00 2001 From: Leynos Date: Wed, 9 Sep 2026 18:20:13 +0100 Subject: [PATCH 1/3] Extend Scrutineer with GitHub Actions monitoring Add explicit run and attempt selection, gh run watch guidance, failed-log capture, and a summary bundle for the summoning agent. Preserve existing gate, CodeRabbit, and provider contracts; pin the new guidance in tests. --- agents/subagents.yml | 169 +++++++++++++++++++++++++++-- tests/test_subagent_definitions.py | 110 +++++++++++++++++++ 2 files changed, 268 insertions(+), 11 deletions(-) diff --git a/agents/subagents.yml b/agents/subagents.yml index 8ef38f5..e45d29b 100644 --- a/agents/subagents.yml +++ b/agents/subagents.yml @@ -616,13 +616,14 @@ agent_tools_subagents: description: >- Runs the repository's deterministic commit gates (formatting, lint, typecheck, unit and behavioural tests, Markdown lint, Mermaid - validation, Molecule role tests) and, when explicitly requested, a - `coderabbit review --agent` pass. Scopes docs-only diffs to the - Markdown gates. Returns a structured summary of failures and - recommended next actions. Use after a code or documentation change - is staged or committed and the planning agent needs an - evidence-backed gate report. Do not use to author code or - documentation; this subagent never edits tracked files. + validation, Molecule role tests). Provides CodeRabbit review monitoring + through an explicitly requested `coderabbit review --agent` pass and + monitors GitHub Actions success/failure with `gh run watch`. Returns + an evidence-backed summary bundle with run results and captured failure + logs to the summoning agent. Scopes docs-only diffs to Markdown gates; + supports monitoring-only assignments for PR and post-merge workflows. + Do not use to author code or documentation; this subagent never edits + tracked files. # TODO(#27): the rate-limit back-off in the instructions below calls # `vsleep`, which is slated to be renamed to `catnap`. Once the `catnap` # rename is finalized, update this instructions body (and regenerate the @@ -631,7 +632,8 @@ agent_tools_subagents: # https://github.com/leynos/agent-helper-scripts/issues/27 instructions: | You are Test Runner, the execution counterpart to a planning agent - that needs a deterministic gate report on the current branch. + that needs deterministic gate, CodeRabbit review, or GitHub Actions + evidence. Return the results and captured logs to the summoning agent. Operating posture: - You never edit tracked files. Your job is to observe, not to @@ -648,6 +650,14 @@ agent_tools_subagents: Makefile targets are the source of truth; do not invent direct tool invocations when a `make` target exists. + Assignment scope: + - A monitoring-only assignment watches the requested GitHub Actions + runs without starting local gates or a new CodeRabbit review. Mark + those activities as not-requested, not as passed or silently skipped. + - For a combined assignment, retain the local gate and CodeRabbit + rules below. A local failure does not prevent collecting evidence + from already-running Actions workflows the summoning agent requested. + Gate selection: - Determine the change surface first. Inspect all three of `git diff --name-only origin/main...HEAD` (committed changes), @@ -726,6 +736,118 @@ agent_tools_subagents: acceptable terminal states are `completed`, `rate-limited`, or `failed-with-error-detail`. + GitHub Actions monitoring (when requested): + - Establish the repository (`OWNER/REPO`), expected commit SHA, PR or + post-merge integration scope, requested workflows or run IDs, and + observation deadline. Use explicit `--repo "$repo"` and run IDs; + never rely on interactive run selection or the current checkout. + - For a PR, read `gh pr view` and `gh pr checks` to identify its current + head, base, and Actions run links. For an explicit commit, discover + runs with `gh run list --repo "$repo" --commit "$expected_sha"`. + Inspect enough results to cover every requested workflow; the default + result limit is not proof of completeness. An empty run list is not + success: report missing or not-yet-created runs at the deadline. + - Before watching, use `gh run view` JSON to record the workflow name, + event, headSha, URL, run ID and attempt. Verify the expected commit + SHA. Never substitute the latest run on a branch for the assigned + candidate. When PR checks use a synthetic merge commit, record its + association with the PR head and base rather than assuming equality. + Keep post-merge integration evidence separate from PR-head evidence. + - Create a private, unique bundle directory under `/tmp` with `mktemp` + and restrictive permissions (`umask 077`). Use the log-slug rules + above, then a separate `run--attempt-` subdirectory for each + run and attempt. Set `bundle_dir` to that subdirectory. Never + overwrite an earlier attempt or another observer's evidence. + - Watch each selected run with `gh run watch`, using a modest refresh + interval and the assignment's time budget. Capture both output + streams and preserve the exit status even under shell errexit: + + ```bash + watch_status=0 + gh run watch "$run_id" --repo "$repo" --exit-status --interval 30 \ + > "$bundle_dir/watch.log" 2>&1 || watch_status=$? + ``` + + - Record the watch command, exit code, and observation timestamps. + A watcher exit code alone is not a workflow verdict: authentication, + network, or API errors can also stop the watcher. On every exit, + including failure, capture an attempt-specific final snapshot: + + ```bash + view_status=0 + gh run view "$run_id" --repo "$repo" --attempt "$attempt" \ + --json status,conclusion,headSha,attempt,jobs,url \ + > "$bundle_dir/run.json" 2> "$bundle_dir/view.stderr" \ + || view_status=$? + ``` + + - Recheck the latest attempt and candidate identity before hand-off. + `gh run watch` does not pin an attempt. If a rerun or rewritten PR + changes that identity, retain the old evidence and report it as stale + or superseded; do not silently transfer its verdict to the new one. + - Only `status=completed` with `conclusion=success` establishes run + success. Preserve failure and all other conclusions, including + cancelled, timed_out, skipped, neutral, action_required, and + startup_failure. Pending, missing, skipped, or inaccessible requested + work must never become an all-success claim. Inspect individual job + results as well, including skipped jobs and allowed failures. + - Surface a failure promptly, then continue observing the other + requested runs within the deadline so the bundle covers the whole + assignment. At the deadline, stop only the local watcher and return + the last known statuses as pending or incomplete. Do not cancel the + hosted run. Record `infrastructure-error` when the CLI, credentials, + permissions, or API prevent observation; do not broaden permissions + or change authentication to make watching work. The CLI documents + that `gh run watch` does not support fine-grained PAT authentication. + + Actions failure logs (mandatory on non-success): + - After a completed non-successful run, capture its failed-step log + using the recorded attempt, even when watching exited nonzero. + Never use `&&` to gate failure-log collection on watcher success: + + ```bash + logs_status=0 + gh run view "$run_id" --repo "$repo" --attempt "$attempt" \ + --log-failed > "$bundle_dir/failed.log" \ + 2> "$bundle_dir/failed-log.stderr" || logs_status=$? + ``` + + - Record the retrieval exit code separately from the Actions conclusion. + If failed-step output is empty or lacks context, use the job ID from + the captured attempt's jobs with + `gh run view --job "$job_id" --repo "$repo" --log`, saving each + job's full log and retrieval stderr to separate files in the bundle. + Do not guess job IDs or attribute an `UNKNOWN STEP` line to a step. + - Capture the failed job and step names, relevant test or file:line, + and up to five decisive log lines per failure. Distinguish observed + errors from suspected causes. Preserve context in the full log. + - Report missing, expired, or inaccessible logs explicitly, including + retrieval errors and run/job URLs. No failed-step output is not proof + of success, especially for cancelled or startup-failed runs. Return + the metadata and partial evidence even when log retrieval fails. + - Do not rerun, cancel, dispatch, approve, or merge as part of this + monitoring assignment. Do not edit workflows, code, or configuration. + The summoning agent owns remediation and any separately authorized + retry; fetching existing evidence is not permission to restart work. + - Keep logs private. Do not upload them or expose credentials, tokens, + or other secrets in excerpts; redact sensitive excerpts and note the + redaction without changing the observed failure's meaning. + + Actions summary bundle: + - Write `summary.md` in the bundle root with the report below and a + manifest of the captured files. For every run, include repository, + workflow, event, expected and observed SHA, run ID, attempt, run URL, + job URLs, status/conclusion, observation timestamps, command exit + codes, and paths to `run.json`, `watch.log`, and captured failure logs. + - Return the bundle root and summary path to the summoning agent with + a concise verdict, failed jobs/steps, decisive excerpts, and evidence + gaps. Provide accessible file attachments when the summoning agent + cannot read the same filesystem; a private local path alone is not + a usable hand-off in that case. + - Preserve each workflow's outcome. A successful run does not erase a + failed sibling, and Actions success does not imply CodeRabbit + approval or successful post-merge integration of a different commit. + Summary discipline: - Surface every failing gate; never claim "all gates passed" when a gate was skipped or errored. @@ -736,6 +858,10 @@ agent_tools_subagents: - Point the planner at the captured log file for any detail beyond the excerpt; never invite a gate re-run to reproduce output that is already on disk. + - Include every requested Actions run in the verdict. Use red for + observed failures, mixed for incomplete evidence without an observed + failure, and green only when all requested work succeeded. Use + not-requested for activities outside a monitoring-only assignment. - End with one concrete next action for the planning agent. Output exactly this structure: @@ -744,11 +870,12 @@ agent_tools_subagents: - Branch: {git branch --show-current} - Working tree: clean | dirty ({N} files) - - Gate scope: full | docs-only | planner-directed, with the paths + - Gate scope: full | docs-only | planner-directed | not-requested, + with the paths or instruction that justified any narrowing - Verdict: green | red | mixed - - Summary: one short paragraph that names the failing gates and - whether a CodeRabbit pass was requested. + - Summary: one short paragraph that names failing gates or Actions + runs and whether CodeRabbit review or Actions monitoring was requested. - Logs: canonical evidence under `/tmp`; read the cited files instead of re-running gates. @@ -781,6 +908,26 @@ agent_tools_subagents: - : + ## GitHub Actions + + - Scope: not-requested | PR checks | post-merge integration | named runs + - Candidate: repository, expected SHA, and observed SHA/PR association + - Observation: start/end timestamps and any deadline reached + - Results: one entry per workflow and run ID/attempt, with its URL, + status, conclusion, failed jobs/steps, and canonical log paths + - Failure evidence: up to five decisive lines per failure, with job URL + and log reference; separate observed errors from suspected causes + - Gaps: pending or missing runs, stale attempts, CLI/API errors, and + unavailable or partial logs; use not-requested when outside scope + + ## Summary Bundle + + - Directory: or not-requested + - Summary: /summary.md + - Manifest: per-run metadata, watch output, failure logs, retrieval + stderr, and their exit codes; name absent files and explain why + - Hand-off: paths or accessible attachments for the summoning agent + ## Next Action Recommend one next step for the planning agent. diff --git a/tests/test_subagent_definitions.py b/tests/test_subagent_definitions.py index 624b093..c77648c 100644 --- a/tests/test_subagent_definitions.py +++ b/tests/test_subagent_definitions.py @@ -416,3 +416,113 @@ def test_scrutineer_report_marks_logs_as_canonical_evidence() -> None: "The report must tell the planner to read the cited log files " "rather than re-running gates, or the delegation saves nothing" ) + +@pytest.mark.parametrize( + "capability", + ( + "deterministic commit gates", + "CodeRabbit review monitoring", + "GitHub Actions", + "gh run watch", + "summary bundle", + ), +) +def test_scrutineer_description_advertises_monitoring(capability: str) -> None: + """Agent selection must expose gates, review monitoring, and Actions watching.""" + entry = load_subagent_entry("scrutineer") + description = _normalized(cast("str", entry["description"])) + + assert capability in description, ( + f"Scrutineer's description must advertise {capability!r}" + ) + +@pytest.mark.parametrize( + "required", + ( + 'gh run watch "$run_id" --repo "$repo" --exit-status', + "--interval 30", + 'gh run view "$run_id" --repo "$repo" --attempt "$attempt"', + "--json status,conclusion,headSha,attempt,jobs,url", + "--log-failed", + 'gh run view --job "$job_id" --repo "$repo" --log', + "watch_status=$?", + "Never use `&&` to gate failure-log collection", + ), +) +def test_scrutineer_actions_commands_preserve_failure_evidence( + required: str, +) -> None: + """Watching and log collection must retain explicit run and exit identities.""" + instructions = _normalized(_scrutineer_instructions()) + + assert required in instructions, ( + f"Scrutineer's Actions instructions must retain {required!r}" + ) + +@pytest.mark.parametrize( + "required", + ( + "expected commit SHA", + "run ID and attempt", + "Never substitute the latest run on a branch", + "synthetic merge commit", + "post-merge integration", + "Only `status=completed` with `conclusion=success`", + "cancelled, timed_out, skipped, neutral, action_required", + "watcher exit code alone is not a workflow verdict", + "An empty run list is not success", + "monitoring-only", + "Do not rerun, cancel, dispatch, approve, or merge", + "infrastructure-error", + ), +) +def test_scrutineer_actions_monitoring_is_candidate_bound_and_read_only( + required: str, +) -> None: + """Missing, stale, or non-successful evidence cannot authorize advancement.""" + instructions = _normalized(_scrutineer_instructions()) + + assert required in instructions, ( + f"Scrutineer's Actions safety contract must retain {required!r}" + ) + +@pytest.mark.parametrize( + "required", + ( + "## GitHub Actions", + "## Summary Bundle", + "summary.md", + "run.json", + "watch.log", + "failed.log", + "failed-log.stderr", + "summoning agent", + "failed job and step names", + "missing, expired, or inaccessible logs", + "not-requested", + "Never overwrite an earlier attempt", + ), +) +def test_scrutineer_actions_handoff_contains_summary_and_captured_logs( + required: str, +) -> None: + """The summoner must receive inspectable evidence rather than a bare verdict.""" + instructions = _normalized(_scrutineer_instructions()) + + assert required in instructions, ( + f"Scrutineer's Actions summary bundle must retain {required!r}" + ) + +def test_scrutineer_retains_local_gates_and_optional_coderabbit_review() -> None: + """Actions monitoring must not weaken gate ownership or review prerequisites.""" + instructions = _normalized(_scrutineer_instructions()) + + for required in ( + "You never edit tracked files", + "Run gates strictly sequentially", + "`coderabbit review --agent`", + "requests a review *and* every applicable deterministic gate", + ): + assert required in instructions, ( + f"Scrutineer's existing execution contract must retain {required!r}" + ) From e456c0922042b6e1e71d3f8896077fc9327b853e Mon Sep 17 00:00:00 2001 From: leynos Date: Thu, 10 Sep 2026 16:14:06 +0200 Subject: [PATCH 2/3] Address review of Scrutineer Actions monitoring Resolve run identity before watching: gh pr checks reports check links, not run identities, so parse each Actions link for its run ID, deduplicate, and verify each candidate with gh run view. Classify non-Actions checks separately and keep exact-commit resolution via gh run list authoritative. Use list literals for the new parametrize argvalues, matching the rest of the module. Document the Scrutineer contract for readers: a user-facing paragraph in docs/users-guide.md covering the three assignment modes, candidate correlation, bounded read-only observation, result semantics, and failure evidence; and a developer-facing operating contract in docs/developers-guide.md covering gate scopes, gh CLI prerequisites, run/attempt correlation, and the evidence bundle layout. --- agents/subagents.yml | 15 +++++++-- docs/developers-guide.md | 51 +++++++++++++++++++++++++++++- docs/users-guide.md | 24 ++++++++++++++ tests/test_subagent_definitions.py | 24 +++++++++----- 4 files changed, 102 insertions(+), 12 deletions(-) diff --git a/agents/subagents.yml b/agents/subagents.yml index e45d29b..083791a 100644 --- a/agents/subagents.yml +++ b/agents/subagents.yml @@ -742,11 +742,20 @@ agent_tools_subagents: observation deadline. Use explicit `--repo "$repo"` and run IDs; never rely on interactive run selection or the current checkout. - For a PR, read `gh pr view` and `gh pr checks` to identify its current - head, base, and Actions run links. For an explicit commit, discover - runs with `gh run list --repo "$repo" --commit "$expected_sha"`. + head, base, and check links. `gh pr checks` reports check links, not + run identities. Parse each Actions link (`/actions/runs/`) for its + run ID, deduplicate the IDs because many jobs share one run, and + confirm each candidate with `gh run view` before recording or watching + it. Classify links that are not Actions runs — external statuses, + deployments, CodeRabbit and similar apps — as non-Actions checks and + exclude them from run monitoring rather than treating them as runs. + For an explicit commit, discover runs with + `gh run list --repo "$repo" --commit "$expected_sha"`; this exact-commit + resolution stays authoritative for commit-scoped assignments. Inspect enough results to cover every requested workflow; the default result limit is not proof of completeness. An empty run list is not - success: report missing or not-yet-created runs at the deadline. + success: report missing or not-yet-created runs at the deadline. Only + verified run identities may enter the watch and evidence steps below. - Before watching, use `gh run view` JSON to record the workflow name, event, headSha, URL, run ID and attempt. Verify the expected commit SHA. Never substitute the latest run on a branch for the assigned diff --git a/docs/developers-guide.md b/docs/developers-guide.md index e033284..850b296 100644 --- a/docs/developers-guide.md +++ b/docs/developers-guide.md @@ -404,7 +404,7 @@ subagents (`wyvern`, `scribe`, `alchemist`, `scrutineer`, `journeyman`, each subagent does and how downstream provisioning renders the manifest, see the `## Sub-agent definitions` section in [docs/users-guide.md](users-guide.md). This section covers the test-loader -concerns only. +concerns and, for the `scrutineer` subagent, its operating contract. The manifest expresses MCP access according to each provider's inheritance model. Claude Code provider blocks use named `mcpServers` allow-lists: every @@ -461,6 +461,55 @@ PyYAML is a development-only dependency, declared as `pyyaml>=6.0.3` in the `[dependency-groups] dev` array of `pyproject.toml`. It is not a runtime dependency of any bootstrap script; only the manifest test helper imports it. +### Scrutineer operating contract + +`scrutineer`'s `instructions` body in `agents/subagents.yml` is the +authoritative source for this contract; it is pinned by +`tests/test_subagent_definitions.py`. An assignment combines up to three +independent scopes: + +- Deterministic local commit gates: `make check-fmt`, `lint`, `typecheck`, + `test`, `markdownlint`, `nixie`, plus `test-podman` when the change + surface touches an Ansible role, module, playbook, or Molecule scenario. +- An optional `coderabbit review --agent` pass, gated on every applicable + deterministic gate above passing first. +- GitHub Actions monitoring. + +A monitoring-only assignment starts neither of the other two scopes and +records them as `not-requested` rather than passed or silently skipped. + +Actions monitoring requires an authenticated `gh` CLI. `gh run watch` does +not support fine-grained PAT authentication, and the agent must never +broaden permissions or change authentication to make watching work. + +Correlation is explicit: repository via `--repo OWNER/REPO`, expected +commit SHA, run ID and attempt. Run identity is resolved by parsing +`gh pr checks` Actions links and verifying each candidate with +`gh run view`, or, for commit-scoped work, via +`gh run list --commit`. `gh run watch` does not pin an attempt, so the +latest attempt and candidate identity are rechecked before hand-off; +superseded evidence is retained and reported as stale rather than +silently transferred to the new attempt. + +Observation is bounded and read-only. An observation deadline stops only +the local watcher; hosted runs are never cancelled. The assignment never +reruns, dispatches, approves, merges, or edits a workflow. + +Only `status=completed` with `conclusion=success` counts as success. Every +other conclusion, and any pending, missing, or inaccessible requested +work, is preserved and never collapsed into an all-success claim. CLI, +credential, permission, and API problems are classified +`infrastructure-error`, distinct from a workflow failure; a nonzero +`gh run watch` exit code is not by itself a verdict. + +Evidence is written to a private `mktemp` directory under `/tmp` created +with `umask 077`, with a `run--attempt-` subdirectory per run and +attempt holding `run.json`, `watch.log`, `failed.log`, and +`failed-log.stderr`, plus a root `summary.md` manifest. Failed-step log +capture is never gated on watcher success with `&&`, and retrieval exit +codes are recorded separately from the observed Actions conclusion. Logs +stay private, and secrets are redacted from any excerpts. + ## Weave Git merge-driver boundary The `weave-git-merge` skill documents Weave, an entity-aware Git merge driver diff --git a/docs/users-guide.md b/docs/users-guide.md index d791853..97ca78d 100644 --- a/docs/users-guide.md +++ b/docs/users-guide.md @@ -500,6 +500,30 @@ stateDiagram-v2 status that follows. A verdict describes one hypothesis; a status describes the whole report.* +`scrutineer` runs a summoned assignment in up to three modes: the +deterministic local commit gates, an optional `coderabbit review --agent` +pass run only when explicitly requested, and GitHub Actions monitoring. A +monitoring-only assignment watches the requested runs without starting +local gates or a new review; those activities are reported as +`not-requested` rather than passed or silently skipped. A docs-only diff, +where every changed path ends in `.md`, scopes the gate set to +`make markdownlint` and `make nixie`. + +Actions monitoring correlates an explicit repository, expected commit +SHA, run ID and attempt; PR-head, synthetic-merge and post-merge +integration evidence are kept distinct, and the latest run on a branch is +never substituted for the assigned candidate. Observation is bounded by a +deadline and is read-only: `scrutineer` never reruns, cancels, dispatches, +approves or merges, and it does not cancel hosted runs at the deadline. +Only `status=completed` with `conclusion=success` counts as success; +pending, cancelled, skipped and neutral states are preserved, and +CLI, credential or API problems are reported as `infrastructure-error` +rather than as a workflow failure. For a non-successful run, failed-step +logs are captured per attempt into a private bundle under `/tmp` +(`summary.md`, `run.json`, `watch.log`, `failed.log`), and missing, +expired or inaccessible logs are reported explicitly rather than read as +success. `scrutineer` never edits tracked files. + `journeyman` delivers one full approved ExecPlan, or one named plateau of it, end-to-end. It may delegate small, bounded, measurable, testable work items to `artisan` agents. diff --git a/tests/test_subagent_definitions.py b/tests/test_subagent_definitions.py index c77648c..fb47963 100644 --- a/tests/test_subagent_definitions.py +++ b/tests/test_subagent_definitions.py @@ -417,15 +417,16 @@ def test_scrutineer_report_marks_logs_as_canonical_evidence() -> None: "rather than re-running gates, or the delegation saves nothing" ) + @pytest.mark.parametrize( "capability", - ( + [ "deterministic commit gates", "CodeRabbit review monitoring", "GitHub Actions", "gh run watch", "summary bundle", - ), + ], ) def test_scrutineer_description_advertises_monitoring(capability: str) -> None: """Agent selection must expose gates, review monitoring, and Actions watching.""" @@ -436,9 +437,10 @@ def test_scrutineer_description_advertises_monitoring(capability: str) -> None: f"Scrutineer's description must advertise {capability!r}" ) + @pytest.mark.parametrize( "required", - ( + [ 'gh run watch "$run_id" --repo "$repo" --exit-status', "--interval 30", 'gh run view "$run_id" --repo "$repo" --attempt "$attempt"', @@ -447,7 +449,7 @@ def test_scrutineer_description_advertises_monitoring(capability: str) -> None: 'gh run view --job "$job_id" --repo "$repo" --log', "watch_status=$?", "Never use `&&` to gate failure-log collection", - ), + ], ) def test_scrutineer_actions_commands_preserve_failure_evidence( required: str, @@ -459,11 +461,15 @@ def test_scrutineer_actions_commands_preserve_failure_evidence( f"Scrutineer's Actions instructions must retain {required!r}" ) + @pytest.mark.parametrize( "required", - ( + [ "expected commit SHA", "run ID and attempt", + "reports check links, not run identities", + "confirm each candidate with `gh run view` before recording", + "non-Actions checks", "Never substitute the latest run on a branch", "synthetic merge commit", "post-merge integration", @@ -474,7 +480,7 @@ def test_scrutineer_actions_commands_preserve_failure_evidence( "monitoring-only", "Do not rerun, cancel, dispatch, approve, or merge", "infrastructure-error", - ), + ], ) def test_scrutineer_actions_monitoring_is_candidate_bound_and_read_only( required: str, @@ -486,9 +492,10 @@ def test_scrutineer_actions_monitoring_is_candidate_bound_and_read_only( f"Scrutineer's Actions safety contract must retain {required!r}" ) + @pytest.mark.parametrize( "required", - ( + [ "## GitHub Actions", "## Summary Bundle", "summary.md", @@ -501,7 +508,7 @@ def test_scrutineer_actions_monitoring_is_candidate_bound_and_read_only( "missing, expired, or inaccessible logs", "not-requested", "Never overwrite an earlier attempt", - ), + ], ) def test_scrutineer_actions_handoff_contains_summary_and_captured_logs( required: str, @@ -513,6 +520,7 @@ def test_scrutineer_actions_handoff_contains_summary_and_captured_logs( f"Scrutineer's Actions summary bundle must retain {required!r}" ) + def test_scrutineer_retains_local_gates_and_optional_coderabbit_review() -> None: """Actions monitoring must not weaken gate ownership or review prerequisites.""" instructions = _normalized(_scrutineer_instructions()) From 0c6df9fae2d9df74a593010fd91a16ef2014996b Mon Sep 17 00:00:00 2001 From: leynos Date: Thu, 10 Sep 2026 17:00:14 +0200 Subject: [PATCH 3/3] Wrap the post-turn-hook URL as an autolink markdownlint reports MD034 (no-bare-urls) for the relocation notice added with the post-turn quality stop hook removal. The repository Makefile has no markdownlint target and `make ci` does not run one, so the violation was not caught on main. Use an angle-bracket autolink, matching how docs/users-guide.md already references the same project. --- docs/developers-guide.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/developers-guide.md b/docs/developers-guide.md index 850b296..1fda522 100644 --- a/docs/developers-guide.md +++ b/docs/developers-guide.md @@ -226,7 +226,8 @@ distinction visible when adding new bootstrap behaviour. - Fetches the requested helper branch before copying hook files. - Copies repository hook files into `~/.claude/hooks`; it no longer registers any hook in Claude Code settings. The post-turn quality stop hook moved to - its own project: https://github.com/leynos/post-turn-quality-stop-hook. + its own project: + . ### `install-skills`