From 1a9c6bd0797dd570032e2e9774fa75101cdc409e Mon Sep 17 00:00:00 2001 From: Stefano Pentassuglia Date: Tue, 22 Sep 2026 17:12:19 +0200 Subject: [PATCH 1/2] chore: initialize fullsend per-repo installation --- .fullsend/config.yaml | 33 ++++++++++ .github/workflows/fullsend.yaml | 106 ++++++++++++++++++++++--------- .github/workflows/prioritize.yml | 51 +++++++++++++++ 3 files changed, 159 insertions(+), 31 deletions(-) create mode 100644 .fullsend/config.yaml create mode 100644 .github/workflows/prioritize.yml diff --git a/.fullsend/config.yaml b/.fullsend/config.yaml new file mode 100644 index 00000000..40298e32 --- /dev/null +++ b/.fullsend/config.yaml @@ -0,0 +1,33 @@ +# fullsend per-repo configuration +# https://github.com/fullsend-ai/fullsend +# +# This file configures fullsend for per-repo installation mode. +# See https://fullsend.sh/docs/guides/infrastructure/layered-config-reference +version: "1" +roles: + - fullsend + - triage + - coder + - fix + - review + - retro + - prioritize +agents: + - name: review + source: customized/harness/review.yaml + - name: retro + source: customized/harness/retro.yaml +allowed_remote_resources: + - https://raw.githubusercontent.com/fullsend-ai/fullsend/ + - https://raw.githubusercontent.com/fullsend-ai/agents/ +create_issues: + allow_targets: + repos: + - conforma/conforma.github.io + - fullsend-ai/fullsend +status_notifications: + comment: + completion: on_failure + reaction: + start: enabled + completion: disabled diff --git a/.github/workflows/fullsend.yaml b/.github/workflows/fullsend.yaml index a755ca1d..11d46287 100644 --- a/.github/workflows/fullsend.yaml +++ b/.github/workflows/fullsend.yaml @@ -1,64 +1,78 @@ -# lint-workflow-size: max-lines=280 -# fullsend shim workflow (workflow_call mode) -# Routes events to agent workflows in .fullsend via workflow_call. -# No secrets are needed in the enrolled repo — agents fetch scoped tokens -# from the centralized token mint using GitHub OIDC. +# This file is managed by fullsend. Do not edit it directly. +# Upstream: https://github.com/fullsend-ai/fullsend/blob/main/internal/scaffold/fullsend-repo/.github/workflows/fullsend.yaml +--- +# fullsend shim workflow (per-repo installation mode) +# Routes events to agent workflows via reusable-dispatch.yml. +# All agent execution happens in this repo's context — no external +# config repo is needed. # # Security: pull_request_target runs the BASE branch version of this workflow, # preventing PRs from modifying it to exfiltrate credentials. # This shim never checks out PR code, so it is not vulnerable to "pwn request" # attacks. # -# conforma is replaced by reconcile-repos.sh at deploy time. +# Routing: this shim forwards the raw event context to reusable-dispatch.yml, +# which determines the stage and runs the agent inline (ADR 62). +# Adding a new stage requires only a job in reusable-dispatch.yml — zero changes to this repo. # -# Routing: this shim forwards the raw event context to dispatch.yml, which -# determines the stage from event_type + event_action + payload fields. -# Adding a new stage requires only a case branch in dispatch.yml — zero -# changes to enrolled repos. +# Concurrency: per-role cancel-in-progress groups live in reusable-dispatch.yml +# stage jobs with -agent- suffix. Roles operate independently (#2452). name: fullsend -permissions: - actions: write - id-token: write - contents: read - pull-requests: read - on: issues: types: [opened, edited, labeled] issue_comment: types: [created] pull_request_target: - types: [opened, synchronize, ready_for_review, closed] + types: [opened, synchronize, ready_for_review, closed, labeled, unlabeled] pull_request_review: types: [submitted] +permissions: {} + jobs: dispatch: - concurrency: - group: fullsend-dispatch-${{ github.event.issue.number || github.event.pull_request.number }} - cancel-in-progress: false if: >- - github.event_name != 'issue_comment' - || github.event.comment.user.type != 'Bot' - uses: conforma/.fullsend/.github/workflows/dispatch.yml@f44ff36aed88e798182d1a316bbfca943c23295a # main + (github.event_name != 'pull_request_target' && github.event_name != 'pull_request_review' + || github.event.pull_request.head.ref != 'fullsend/scaffold-install') + && (github.event_name != 'issue_comment' + || (startsWith(github.event.comment.body, '/fs-') + && github.event.comment.user.type != 'Bot')) + permissions: + actions: write + id-token: write + contents: write + issues: write + packages: read + pull-requests: write + uses: fullsend-ai/fullsend/.github/workflows/reusable-dispatch.yml@main with: event_action: ${{ github.event.action }} + install_mode: per-repo + mint_url: ${{ vars.FULLSEND_MINT_URL }} + gcp_region: ${{ vars.FULLSEND_GCP_REGION }} + project_number: ${{ vars.FULLSEND_PROJECT_NUMBER }} + runner_image: ubuntu-24.04 + secrets: + FULLSEND_GCP_WIF_PROVIDER: ${{ secrets.FULLSEND_GCP_WIF_PROVIDER }} + FULLSEND_GCP_PROJECT_ID: ${{ secrets.FULLSEND_GCP_PROJECT_ID }} + FULLSEND_OPENAI_API_KEY: ${{ secrets.FULLSEND_OPENAI_API_KEY }} + OTEL_EXPORTER_OTLP_TRACES_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_TRACES_HEADERS }} + OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }} stop-fix: + # Job-level if: is intentionally coarse — it only screens for the + # /fs-fix-stop command on a PR from a non-bot. The authoritative + # authorization decision (collaborator permission API + PR-author escape + # hatch) is made in the step below, so a maintainer whose author_association + # is not MEMBER (e.g. private org membership) is not filtered out (ADR 0054). if: >- github.event_name == 'issue_comment' && github.event.issue.pull_request && github.event.comment.user.type != 'Bot' && github.event.comment.body == '/fs-fix-stop' - && ( - github.event.comment.author_association == 'OWNER' - || github.event.comment.author_association == 'MEMBER' - || github.event.comment.author_association == 'COLLABORATOR' - || github.event.comment.author_association == 'CONTRIBUTOR' - || github.event.comment.user.login == github.event.issue.user.login - ) - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: contents: read issues: write @@ -69,7 +83,37 @@ jobs: GH_TOKEN: ${{ github.token }} PR_NUMBER: ${{ github.event.issue.number }} REPO: ${{ github.repository }} + COMMENT_USER_LOGIN: ${{ github.event.comment.user.login }} + ISSUE_USER_LOGIN: ${{ github.event.issue.user.login }} run: | + set -euo pipefail + # ADR 0054: authorize via the collaborator permission API + # (admin|maintain|write), not author_association — the latter grants + # contributor status to anyone with a single merged PR (issue #5421). + # Mirrors has_repo_permission() in dispatch.yml; keep the two in sync. + # The PR author may always stop the fix agent on their own PR. + authorized=false + if [[ -n "$COMMENT_USER_LOGIN" && "$COMMENT_USER_LOGIN" == "$ISSUE_USER_LOGIN" ]]; then + authorized=true + else + if api_err=$(mktemp); then + if role=$(gh api "repos/$REPO/collaborators/$COMMENT_USER_LOGIN/permission" \ + --jq '.role_name' 2>"$api_err"); then + case "$role" in + admin|maintain|write) authorized=true ;; + esac + else + echo "::warning::Permission API call failed for $COMMENT_USER_LOGIN: $(cat "$api_err")" + fi + rm -f "$api_err" + else + echo "::warning::Failed to create temp file for permission check of $COMMENT_USER_LOGIN" + fi + fi + if [[ "$authorized" != "true" ]]; then + echo "::notice::User $COMMENT_USER_LOGIN is not authorized to stop the fix agent (requires write access or PR authorship)" + exit 0 + fi gh label create "fullsend-no-fix" --repo "$REPO" \ --description "Skip bot-triggered fix agent runs" --color "FBCA04" \ --force 2>/dev/null || true diff --git a/.github/workflows/prioritize.yml b/.github/workflows/prioritize.yml new file mode 100644 index 00000000..0330deb3 --- /dev/null +++ b/.github/workflows/prioritize.yml @@ -0,0 +1,51 @@ +# This file is managed by fullsend. Do not edit it directly. +# Upstream: https://github.com/fullsend-ai/fullsend/blob/main/internal/scaffold/fullsend-repo/.github/workflows/prioritize.yml +--- +# fullsend-stage: prioritize +name: Prioritize + +permissions: + actions: write + contents: read + id-token: write + issues: write + +on: + workflow_dispatch: + inputs: + event_type: + required: true + type: string + source_repo: + required: true + type: string + event_payload: + required: true + type: string + project_number: + description: GitHub Projects V2 project number for RICE scoring + required: false + type: string + +concurrency: + group: fullsend-prioritize-${{ inputs.source_repo }}-${{ fromJSON(inputs.event_payload).issue.number }} + cancel-in-progress: true + +jobs: + prioritize: + uses: fullsend-ai/fullsend/.github/workflows/reusable-prioritize.yml@main + with: + event_type: ${{ inputs.event_type }} + source_repo: ${{ inputs.source_repo }} + event_payload: ${{ inputs.event_payload }} + mint_url: ${{ vars.FULLSEND_MINT_URL }} + gcp_region: ${{ vars.FULLSEND_GCP_REGION }} + project_number: ${{ inputs.project_number || vars.FULLSEND_PROJECT_NUMBER }} + install_mode: per-repo + runner_image: ubuntu-24.04 + secrets: + FULLSEND_GCP_WIF_PROVIDER: ${{ secrets.FULLSEND_GCP_WIF_PROVIDER }} + FULLSEND_GCP_PROJECT_ID: ${{ secrets.FULLSEND_GCP_PROJECT_ID }} + FULLSEND_OPENAI_API_KEY: ${{ secrets.FULLSEND_OPENAI_API_KEY }} + OTEL_EXPORTER_OTLP_TRACES_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_TRACES_HEADERS }} + OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }} From ceec97ac43a795bac3955c2935b5c6d3c91d6b6e Mon Sep 17 00:00:00 2001 From: Stefano Pentassuglia Date: Wed, 23 Sep 2026 13:47:04 +0000 Subject: [PATCH 2/2] Add Fullsend tuning and license headers Co-Authored-By: gpt-6-luna --- .fullsend/config.yaml | 16 +++++ .fullsend/customized/harness/retro.yaml | 21 ++++++ .fullsend/customized/harness/review.yaml | 27 ++++++++ .../skills/retro-filing-policy/SKILL.md | 66 +++++++++++++++++++ .github/workflows/fullsend.yaml | 16 +++++ .github/workflows/prioritize.yml | 16 +++++ AGENTS.md | 7 ++ 7 files changed, 169 insertions(+) create mode 100644 .fullsend/customized/harness/retro.yaml create mode 100644 .fullsend/customized/harness/review.yaml create mode 100644 .fullsend/customized/skills/retro-filing-policy/SKILL.md create mode 100644 AGENTS.md diff --git a/.fullsend/config.yaml b/.fullsend/config.yaml index 40298e32..b039399c 100644 --- a/.fullsend/config.yaml +++ b/.fullsend/config.yaml @@ -1,3 +1,19 @@ +# Copyright The Conforma Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + # fullsend per-repo configuration # https://github.com/fullsend-ai/fullsend # diff --git a/.fullsend/customized/harness/retro.yaml b/.fullsend/customized/harness/retro.yaml new file mode 100644 index 00000000..84de615b --- /dev/null +++ b/.fullsend/customized/harness/retro.yaml @@ -0,0 +1,21 @@ +# Copyright The Conforma Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +# Derived retro harness: retain upstream analysis and append the Conforma gate. +base: https://raw.githubusercontent.com/fullsend-ai/agents/69ade99f1b61bea99aee98e604384e26ff7b45e0/harness/retro.yaml#sha256=6d858c90cc6f1c7526d2b36b8cd47df079d1332ac7184bb70dfb1587e9cb04d8 + +skills: + - customized/skills/retro-filing-policy diff --git a/.fullsend/customized/harness/review.yaml b/.fullsend/customized/harness/review.yaml new file mode 100644 index 00000000..e49d188f --- /dev/null +++ b/.fullsend/customized/harness/review.yaml @@ -0,0 +1,27 @@ +# Copyright The Conforma Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +base: https://raw.githubusercontent.com/fullsend-ai/agents/440d3e3c1a4a770309e37c2fd2826dfc88297d99/harness/review.yaml#sha256=c259d94e7c50e5e01cb0fa38df2b70765f8e35beb7ad8bf006c9193a05589917 + +# Fullsend's bool merge treats an omitted readonly_repo as false, so carry +# forward the upstream read-only guarantee explicitly. +readonly_repo: true + +env: + runner: + REVIEW_FINDING_SEVERITY_THRESHOLD: "high" + sandbox: + REVIEW_FINDING_SEVERITY_THRESHOLD: "high" diff --git a/.fullsend/customized/skills/retro-filing-policy/SKILL.md b/.fullsend/customized/skills/retro-filing-policy/SKILL.md new file mode 100644 index 00000000..bd16ce06 --- /dev/null +++ b/.fullsend/customized/skills/retro-filing-policy/SKILL.md @@ -0,0 +1,66 @@ +--- +name: retro-filing-policy +description: >- + Required on every Conforma retro run. Score every candidate from 0 to 5 + and file only score-4 and score-5 findings after duplicate checks. +--- + +# Conforma retro filing policy + +This skill is mandatory for every retro run. Invoke it before writing +`$FULLSEND_OUTPUT_DIR/agent-result.json`. It augments the upstream retro +analysis and does not replace its workflow reconstruction, duplicate checks, +recently-closed checks, evidence handling, or proposal limit. + +## Required filing sequence + +1. Build the complete candidate list from the upstream retro analysis. +2. Before deciding what belongs in `proposals[]`, assign every candidate an + integer judge score from 0 through 5 using the rubric below. +3. Apply the upstream checks for an existing open duplicate or a substantially + equivalent issue closed recently. A duplicate or recently closed equivalent + is summary-only even when its score is 4 or 5. Supporting evidence for an + existing issue is summary-only and must never become an "Evidence for ..." + proposal. +4. Put only eligible, non-duplicate candidates scored 4 or 5 in `proposals[]`. + Preserve the upstream maximum of three proposals, keeping the highest-value + candidates when there are more than three. +5. Keep every score-0-through-3 candidate out of `proposals[]`. Mention it in + the retro `summary` as summary-only, with a compact reason. +6. In the `summary`, include a compact **Judge scores** list covering every + candidate, filed and summary-only. Each entry must contain the score, a + short title, and the disposition (`filed` or `summary-only`). +7. For every filed proposal, begin the existing + `what_could_go_better` text field with: + + `Judge score: N/5 — ` + + Do not add new JSON fields or change the upstream result schema. + +Do not create, edit, or post issues yourself. The upstream post-script handles +writes after output validation. + +## Conforma scoring rubric + +Score the impact of the candidate, not how interesting the observation is. +Use the lower range by default for isolated improvements: + +- One-off pitfalls, cosmetic documentation edits, historical-document + cleanup, speculative prevention rules, and isolated preferences score 0–3 + by default. They are not eligible for filing without evidence that a higher + threshold applies. +- An `AGENTS.md` proposal scores 0–3 by default. It can score 4 or 5 only + when there is evidence of a recurring contributor or agent failure, the rule + applies to human contributors as well as bots, and the instruction has a + credible preventive mechanism. + +Use score 4 only when there is a likely recurring impact, such as repeated +human time loss, repeated bad bot output, pipeline or policy integrity risk, +or persistent operational cost. + +Use score 5 only for a systemic or recurring correctness, security, +reliability, or policy failure. + +A high score does not bypass the upstream duplicate, recently-closed, or +evidence-for checks. If those checks suppress a candidate, list it as +summary-only and explain the disposition in the summary. diff --git a/.github/workflows/fullsend.yaml b/.github/workflows/fullsend.yaml index 11d46287..f4583da4 100644 --- a/.github/workflows/fullsend.yaml +++ b/.github/workflows/fullsend.yaml @@ -1,3 +1,19 @@ +# Copyright The Conforma Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + # This file is managed by fullsend. Do not edit it directly. # Upstream: https://github.com/fullsend-ai/fullsend/blob/main/internal/scaffold/fullsend-repo/.github/workflows/fullsend.yaml --- diff --git a/.github/workflows/prioritize.yml b/.github/workflows/prioritize.yml index 0330deb3..553efd24 100644 --- a/.github/workflows/prioritize.yml +++ b/.github/workflows/prioritize.yml @@ -1,3 +1,19 @@ +# Copyright The Conforma Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + # This file is managed by fullsend. Do not edit it directly. # Upstream: https://github.com/fullsend-ai/fullsend/blob/main/internal/scaffold/fullsend-repo/.github/workflows/prioritize.yml --- diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..de6a6d96 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,7 @@ +## Retro filing + +When running as the `retro` agent, invoke the `retro-filing-policy` skill +before writing output. It is loaded by the derived retro harness and is the +enforcement layer; this pointer is only reinforcement. Scores 0–3 are +summary-only, while scores 4–5 remain subject to the upstream duplicate and +recently-closed checks before filing.