Skip to content

[runx] refresh evidence projections #38

[runx] refresh evidence projections

[runx] refresh evidence projections #38

Workflow file for this run

name: docs-pr
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
on:
issues:
types:
- opened
- edited
- reopened
issue_comment:
types:
- created
workflow_dispatch:
inputs:
issue_number:
description: Work issue number in this repo. The issue is the living ledger for this docs change.
required: true
type: string
permissions:
actions: write
contents: write
issues: write
pull-requests: write
concurrency:
group: docs-pr-${{ github.event.issue.number || github.event.inputs.issue_number || github.ref_name }}
cancel-in-progress: ${{ github.event_name != 'issue_comment' }}
jobs:
docs-pr:
if: >-
${{
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'issues' &&
startsWith(github.event.issue.title, '[docs]')
) ||
(
github.event_name == 'issue_comment' &&
github.event.issue.pull_request == null &&
github.event.comment.user.type != 'Bot' &&
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) &&
!contains(github.event.comment.body, '<!-- aster:runx-skill-lab -->') &&
!contains(github.event.comment.body, '<!-- aster:runx-issue-triage -->') &&
!contains(github.event.comment.body, '<!-- aster:runx-work-lane:') &&
startsWith(github.event.issue.title, '[docs]')
)
}}
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.ASTER_GH_TOKEN != '' && secrets.ASTER_GH_TOKEN || secrets.RUNX_REPOSITORY_PAT || github.token }}
RUNX_CALLER_MODEL: ${{ vars.RUNX_CALLER_MODEL || 'gpt-5.4' }}
RUNX_CALLER_REASONING_EFFORT: ${{ vars.RUNX_CALLER_REASONING_EFFORT || 'xhigh' }}
RUNX_CALLER_MAX_ATTEMPTS: ${{ vars.RUNX_CALLER_MAX_ATTEMPTS || '3' }}
RUNX_CALLER_REQUEST_TIMEOUT_MS: ${{ vars.RUNX_CALLER_REQUEST_TIMEOUT_MS || '300000' }}
steps:
- name: Check lane prerequisites
id: preflight
env:
HAS_OPENAI_KEY: ${{ secrets.OPENAI_API_KEY != '' }}
run: |
if [ "${HAS_OPENAI_KEY}" != "true" ]; then
echo "enabled=false" >> "$GITHUB_OUTPUT"
echo "OPENAI_API_KEY not configured; skipping docs-pr."
else
echo "enabled=true" >> "$GITHUB_OUTPUT"
fi
- name: Check out aster
if: ${{ steps.preflight.outputs.enabled == 'true' }}
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Check out runx
if: ${{ steps.preflight.outputs.enabled == 'true' }}
uses: actions/checkout@v6
with:
repository: ${{ vars.RUNX_REPOSITORY || 'runxhq/runx' }}
ref: ${{ vars.RUNX_REF || 'main' }}
path: .runx/runx
token: ${{ secrets.RUNX_REPOSITORY_PAT || github.token }}
- name: Set up Node.js
if: ${{ steps.preflight.outputs.enabled == 'true' }}
uses: actions/setup-node@v6
with:
node-version: 24
- name: Enable corepack
if: ${{ steps.preflight.outputs.enabled == 'true' }}
run: corepack enable
- name: Install and build runx
if: ${{ steps.preflight.outputs.enabled == 'true' }}
run: |
pnpm --dir .runx/runx install --no-frozen-lockfile
pnpm --dir .runx/runx build
- name: Install scafld
if: ${{ steps.preflight.outputs.enabled == 'true' }}
run: |
curl -fsSL https://raw.githubusercontent.com/nilstate/scafld/main/install.sh | sh
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
"$HOME/.local/bin/scafld" --version
- name: Configure git author
if: ${{ steps.preflight.outputs.enabled == 'true' }}
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Resolve issue envelope
if: ${{ steps.preflight.outputs.enabled == 'true' }}
id: issue
run: |
mkdir -p .artifacts/docs-pr
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
ISSUE_NUMBER="${{ github.event.inputs.issue_number }}"
else
ISSUE_NUMBER="${{ github.event.issue.number }}"
fi
gh issue view "$ISSUE_NUMBER" \
--repo "${{ github.repository }}" \
--json number,title,body,url \
> .artifacts/docs-pr/issue.json
echo "number=$(jq -r '.number' .artifacts/docs-pr/issue.json)" >> "$GITHUB_OUTPUT"
echo "title<<EOF" >> "$GITHUB_OUTPUT"
jq -r '.title' .artifacts/docs-pr/issue.json >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
echo "body<<EOF" >> "$GITHUB_OUTPUT"
jq -r '.body // ""' .artifacts/docs-pr/issue.json >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
echo "url=$(jq -r '.url' .artifacts/docs-pr/issue.json)" >> "$GITHUB_OUTPUT"
- name: Build issue ledger
if: ${{ steps.preflight.outputs.enabled == 'true' }}
id: issue_ledger
run: |
node scripts/issue-ledger.mjs \
--repo "${{ github.repository }}" \
--issue "${{ steps.issue.outputs.number }}" \
--output .artifacts/docs-pr/issue-ledger.json
echo "ledger_revision=$(jq -r '.ledger_revision' .artifacts/docs-pr/issue-ledger.json)" >> "$GITHUB_OUTPUT"
- name: Prepare work issue request
if: ${{ steps.preflight.outputs.enabled == 'true' }}
id: request
run: |
node scripts/prepare-work-issue-request.mjs \
--input .artifacts/docs-pr/issue-ledger.json \
--lane docs-pr \
--default-target-repo "${{ github.repository }}" \
--default-source-repo "${{ github.repository }}" \
--output .artifacts/docs-pr/work-issue-request.json
echo "request_title=$(jq -r '.request_title' .artifacts/docs-pr/work-issue-request.json)" >> "$GITHUB_OUTPUT"
echo "target_repo=$(jq -r '.target_repo' .artifacts/docs-pr/work-issue-request.json)" >> "$GITHUB_OUTPUT"
- name: Check work issue authorization
if: ${{ steps.preflight.outputs.enabled == 'true' }}
id: gate
run: |
node scripts/check-thread-teaching-gate.mjs \
--repo "${{ github.repository }}" \
--issue "${{ steps.issue.outputs.number }}" \
--target-repo "${{ steps.request.outputs.target_repo }}" \
--subject-locator "${{ steps.request.outputs.target_repo }}" \
--applies-to "docs-pr.publish" \
--output .artifacts/docs-pr/thread-teaching-gate.json
jq '.context' .artifacts/docs-pr/thread-teaching-gate.json > .artifacts/docs-pr/thread-teaching-context.json
if jq -e '.allowed == true' .artifacts/docs-pr/thread-teaching-gate.json > /dev/null; then
echo "allowed=true" >> "$GITHUB_OUTPUT"
else
echo "allowed=false" >> "$GITHUB_OUTPUT"
echo "Docs proposal refreshed without draft PR publication." >> "$GITHUB_STEP_SUMMARY"
echo "Reply in the same work issue with trusted \`Applies To:\` + \`Decision:\` lines, or a full thread-teaching record, that authorizes \`docs-pr.publish\` to refresh the draft PR." >> "$GITHUB_STEP_SUMMARY"
fi
- name: Run docs-pr lane
if: ${{ steps.preflight.outputs.enabled == 'true' }}
timeout-minutes: 45
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
set -euo pipefail
args=(
--lane docs-pr
--runx-root "$GITHUB_WORKSPACE/.runx/runx"
--default-repo "${{ github.repository }}"
--request-file "$GITHUB_WORKSPACE/.artifacts/docs-pr/work-issue-request.json"
--thread-teaching-context-file "$GITHUB_WORKSPACE/.artifacts/docs-pr/thread-teaching-context.json"
--artifact-root "$GITHUB_WORKSPACE/.artifacts/docs-pr"
--work-root "$GITHUB_WORKSPACE/.artifacts/docs-pr-workspaces"
--publish "${{ steps.gate.outputs.allowed == 'true' && 'true' || 'false' }}"
--scafld-bin "$HOME/.local/bin/scafld"
)
if [ "${{ steps.gate.outputs.allowed }}" != "true" ]; then
args+=(--publish-reason "docs-pr.publish gate not granted yet")
fi
node scripts/run-governed-pr-lane.mjs "${args[@]}" > .artifacts/docs-pr/result-summary.json
cat .artifacts/docs-pr/result-summary.json
- name: Post rolling work issue comment
if: ${{ always() && steps.preflight.outputs.enabled == 'true' }}
run: |
set -euo pipefail
args=(
--repo "${{ github.repository }}"
--issue "${{ steps.issue.outputs.number }}"
--lane docs-pr
--workflow-status "${{ job.status }}"
--run-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
)
if [ -n "${{ steps.request.outputs.request_title }}" ]; then
args+=(--request-title "${{ steps.request.outputs.request_title }}")
fi
if [ -n "${{ steps.request.outputs.target_repo }}" ]; then
args+=(--target-repo "${{ steps.request.outputs.target_repo }}")
fi
if [ -n "${{ steps.issue_ledger.outputs.ledger_revision }}" ]; then
args+=(--ledger-revision "${{ steps.issue_ledger.outputs.ledger_revision }}")
fi
if [ -f ".artifacts/docs-pr/result-summary.json" ]; then
args+=(--result-json ".artifacts/docs-pr/result-summary.json")
fi
node scripts/post-work-issue-lane-comment.mjs "${args[@]}"
- name: Publish evidence
if: ${{ always() && steps.preflight.outputs.enabled == 'true' }}
env:
RUNX_PUBLIC_EVIDENCE_API_BASE_URL: ${{ vars.RUNX_PUBLIC_EVIDENCE_API_BASE_URL || 'https://api.runx.ai' }}
RUNX_PUBLIC_EVIDENCE_TOKEN: ${{ secrets.RUNX_PUBLIC_EVIDENCE_TOKEN }}
run: |
STATUS="${{ job.status }}"
TARGET="${{ steps.request.outputs.target_repo || github.repository }}"
PUBLISH_STATUS=""
if [ -f ".artifacts/docs-pr/result-summary.json" ]; then
PUBLISH_STATUS="$(jq -r '.publish.status // ""' .artifacts/docs-pr/result-summary.json)"
fi
if [ "$STATUS" = "success" ] && [ "$PUBLISH_STATUS" = "published" ]; then
TITLE="opened a docs PR on ${TARGET}"
SUMMARY="drafted a bounded docs improvement from the work issue ledger and refreshed one review-ready PR"
elif [ "$STATUS" = "success" ]; then
TITLE="refreshed a docs proposal on ${TARGET}"
SUMMARY="drafted a bounded docs improvement from the work issue ledger without refreshing a draft PR"
else
TITLE="docs PR failed on ${TARGET}"
SUMMARY="docs-pr lane failed during execution"
fi
curl --fail --silent --show-error \
-X POST \
-H "authorization: Bearer ${RUNX_PUBLIC_EVIDENCE_TOKEN}" \
-H "content-type: application/json" \
--data "$(jq -n \
--arg title "$TITLE" --arg summary "$SUMMARY" --arg status "$STATUS" \
--arg repo "$TARGET" --arg url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
'{events: [{kind: "aster_run", source: "github-actions", status: (if $status == "success" then "success" else "failure" end), title: $title, summary: $summary, repo: $repo, workflow: "docs-pr", url: $url, timestamp: (now | todate), metadata: {lane: "docs-pr", feed_channel: "main", main_feed_eligible: true}}]}')" \
"${RUNX_PUBLIC_EVIDENCE_API_BASE_URL%/}/v1/admin/public/evidence" || true
- name: Upload artifacts
if: ${{ always() && steps.preflight.outputs.enabled == 'true' }}
uses: actions/upload-artifact@v7
with:
name: docs-pr-${{ steps.issue.outputs.number || github.event.issue.number || github.event.inputs.issue_number }}
path: .artifacts/docs-pr