Skip to content

feat: add durable issue development loop #26

feat: add durable issue development loop

feat: add durable issue development loop #26

name: Issue dev loop evidence
on:
pull_request:
branches: [dev]
types: [opened, synchronize, reopened, ready_for_review]
permissions:
contents: read
concurrency:
group: issue-dev-loop-evidence-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
bootstrap-evidence:
if: >-
github.event_name == 'pull_request' &&
github.head_ref == 'codex/issue-dev-loop' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.pull_request.user.login == 'codeacme17'
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Check out bootstrap PR head
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
persist-credentials: false
- name: Assert immutable bootstrap head
run: test "$(git rev-parse HEAD)" = "${{ github.event.pull_request.head.sha }}"
- name: Set up pnpm
uses: pnpm/action-setup@v6
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile --ignore-scripts
- name: Run bootstrap verification
run: pnpm verify
evidence:
if: github.event_name == 'pull_request' && startsWith(github.event.pull_request.head.ref, 'codex/issue-') && github.event.pull_request.head.ref != 'codex/issue-dev-loop'
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- name: Check out owner-merged control plane
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.base.sha }}
fetch-depth: 0
path: control
persist-credentials: false
- name: Check out exact PR head
uses: actions/checkout@v6
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
path: candidate
persist-credentials: false
- name: Set up trusted Node
uses: actions/setup-node@v6
with:
node-version: 24
- name: Resolve loop run
id: run
env:
PR_HEAD_REF: ${{ github.event.pull_request.head.ref }}
run: >-
node control/loops/issue-dev-loop/scripts/resolve-run.mjs --loop-root candidate/loops/issue-dev-loop --branch "$PR_HEAD_REF"
- name: Require one active run
run: test "${{ steps.run.outputs.has_run }}" = "true"
- name: Check out frozen owner-merged baseline
uses: actions/checkout@v6
with:
ref: ${{ steps.run.outputs.base_sha }}
fetch-depth: 1
path: trusted
persist-credentials: false
- name: Assert immutable head and trusted baseline
env:
FROZEN_BASE_SHA: ${{ steps.run.outputs.base_sha }}
LIVE_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
test "$(git -C candidate rev-parse HEAD)" = "${PR_HEAD_SHA}"
test "$(git -C trusted rev-parse HEAD)" = "${FROZEN_BASE_SHA}"
git -C control merge-base --is-ancestor "${FROZEN_BASE_SHA}" "${LIVE_BASE_SHA}"
- name: Protect trusted control plane
if: steps.run.outputs.has_run == 'true'
run: >-
node trusted/loops/issue-dev-loop/scripts/validate-candidate-control-plane.mjs --loop-root candidate/loops/issue-dev-loop --run-id "${{ steps.run.outputs.run_id }}" --base-sha "${{ steps.run.outputs.base_sha }}" --head-sha "${{ github.event.pull_request.head.sha }}"
- name: Protect append-only loop history
if: steps.run.outputs.has_run == 'true'
run: >-
node trusted/loops/issue-dev-loop/scripts/validate-history.mjs --loop-root candidate/loops/issue-dev-loop --base-ref "${{ steps.run.outputs.base_sha }}"
- name: Build trusted verifier image
run: >-
docker build --tag echo-ui-loop-verifier:${{ github.run_id }}-${{ github.run_attempt }} --file trusted/loops/issue-dev-loop/scripts/verifier.Dockerfile trusted/loops/issue-dev-loop/scripts
- name: Prepare isolated candidate and baseline volumes
shell: bash
run: |
candidate_volume="issue-dev-loop-candidate-${{ github.run_id }}-${{ github.run_attempt }}"
baseline_volume="issue-dev-loop-baseline-${{ github.run_id }}-${{ github.run_attempt }}"
image="echo-ui-loop-verifier:${{ github.run_id }}-${{ github.run_attempt }}"
docker volume create "${candidate_volume}"
docker volume create "${baseline_volume}"
docker run --rm \
--mount "type=volume,src=${candidate_volume},dst=/work" \
--mount "type=bind,src=${GITHUB_WORKSPACE}/candidate,dst=/source,readonly" \
"${image}" \
sh -ceu 'cp -a /source/. /work/; cd /work; pnpm install --frozen-lockfile --ignore-scripts'
docker run --rm \
--mount "type=volume,src=${baseline_volume},dst=/work" \
--mount "type=bind,src=${GITHUB_WORKSPACE}/trusted,dst=/source,readonly" \
"${image}" \
sh -ceu 'cp -a /source/. /work/; cd /work; pnpm install --frozen-lockfile --ignore-scripts'
- name: Run authoritative verification
id: verify
shell: bash
run: |
mkdir -p "${RUNNER_TEMP}/issue-dev-evidence"
started_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
candidate_volume="issue-dev-loop-candidate-${{ github.run_id }}-${{ github.run_attempt }}"
baseline_volume="issue-dev-loop-baseline-${{ github.run_id }}-${{ github.run_attempt }}"
image="echo-ui-loop-verifier:${{ github.run_id }}-${{ github.run_attempt }}"
set +e
docker run --rm --network none \
--mount "type=volume,src=${candidate_volume},dst=/work" \
"${image}" \
pnpm verify 2>&1 | tee "${RUNNER_TEMP}/issue-dev-evidence/pnpm-verify.log"
candidate_exit_code="${PIPESTATUS[0]}"
set -e
baseline_status=blocked
baseline_exit_code=1
if [[ "${candidate_exit_code}" == "0" ]]; then
set +e
docker run --rm --network none \
--mount "type=volume,src=${baseline_volume},dst=/work" \
"${image}" \
pnpm test 2>&1 | tee "${RUNNER_TEMP}/issue-dev-evidence/owner-merged-baseline-tests.log"
baseline_exit_code="${PIPESTATUS[0]}"
set -e
if [[ "${baseline_exit_code}" == "0" ]]; then
baseline_status=passed
else
baseline_status=failed
fi
fi
if [[ "${candidate_exit_code}" == "0" && "${baseline_exit_code}" == "0" ]]; then
exit_code=0
else
exit_code=1
fi
finished_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
if [[ "${exit_code}" == "0" ]]; then verdict=passed; else verdict=failed; fi
echo "started_at=${started_at}" >> "${GITHUB_OUTPUT}"
echo "finished_at=${finished_at}" >> "${GITHUB_OUTPUT}"
echo "exit_code=${exit_code}" >> "${GITHUB_OUTPUT}"
echo "verdict=${verdict}" >> "${GITHUB_OUTPUT}"
echo "baseline_status=${baseline_status}" >> "${GITHUB_OUTPUT}"
- name: Remove isolated verifier volumes
if: always()
run: |
docker volume rm --force "issue-dev-loop-candidate-${{ github.run_id }}-${{ github.run_attempt }}"
docker volume rm --force "issue-dev-loop-baseline-${{ github.run_id }}-${{ github.run_attempt }}"
- name: Generate exact-head manifest
if: steps.run.outputs.has_run == 'true' && always()
run: >-
node trusted/loops/issue-dev-loop/scripts/generate-evidence.mjs --loop-root candidate/loops/issue-dev-loop --run-id "${{ steps.run.outputs.run_id }}" --head-sha "${{ github.event.pull_request.head.sha }}" --trusted-workflow-sha "${{ steps.run.outputs.base_sha }}" --workflow-base-sha "${{ github.event.pull_request.base.sha }}" --workflow-run-sha "${{ github.event.pull_request.head.sha }}" --status "${{ steps.verify.outputs.verdict || 'blocked' }}" --baseline-status "${{ steps.verify.outputs.baseline_status || 'blocked' }}" --started-at "${{ steps.verify.outputs.started_at || github.event.pull_request.updated_at }}" --finished-at "${{ steps.verify.outputs.finished_at || github.event.pull_request.updated_at }}" --output "${RUNNER_TEMP}/issue-dev-evidence/manifest.json"
- name: Upload review evidence
if: steps.run.outputs.has_run == 'true' && always()
id: artifact
uses: actions/upload-artifact@v4
with:
name: issue-dev-loop-${{ steps.run.outputs.run_id }}-${{ github.event.pull_request.head.sha }}
path: |
${{ runner.temp }}/issue-dev-evidence
candidate/loops/issue-dev-loop/screen-shots/${{ steps.run.outputs.run_id }}
candidate/loops/issue-dev-loop/logs/runs/${{ steps.run.outputs.run_id }}
if-no-files-found: error
retention-days: 30
- name: Publish artifact link
if: steps.run.outputs.has_run == 'true' && always()
run: echo "Evidence artifact — ${{ steps.artifact.outputs.artifact-url }}" >> "${GITHUB_STEP_SUMMARY}"
- name: Enforce verification result
if: steps.verify.outputs.exit_code != '0'
run: exit 1