Skip to content

fix: Docker sandbox agent execution + role template rendering + --model propagation for non-Claude CLIs #682

fix: Docker sandbox agent execution + role template rendering + --model propagation for non-Claude CLIs

fix: Docker sandbox agent execution + role template rendering + --model propagation for non-Claude CLIs #682

Workflow file for this run

name: docs-drift
# Reads the doc inventory in docs/playbooks/docs-drift.md and checks that
# every source-of-truth file referenced by a doc still exists, that the
# canonical AGENTS.md / CLAUDE.md / CONVENTIONS.md / .goosehints /
# .cursor/rules/*.mdc outputs agree with `bernstein agents-md verify`, and
# that every enumerated doc file is present on disk. On pull requests the
# report is posted as a non-blocking PR comment so the change can land in
# the same PR. On pushes to main the gate fails so the drift gets fixed in
# a follow-up.
on:
pull_request:
paths:
- "docs/**"
- "src/bernstein/**"
- "scripts/check_docs_drift.py"
- "scripts/check_data_freshness.py"
- "scripts/gen_agents_md.py"
- ".github/workflows/docs-drift.yml"
- "AGENTS.md"
- "CLAUDE.md"
- "CONVENTIONS.md"
- ".goosehints"
- "README.md"
- "CONTRIBUTING.md"
push:
branches: [main]
paths:
- "docs/**"
- "src/bernstein/**"
- "scripts/check_docs_drift.py"
- "scripts/check_data_freshness.py"
- "scripts/gen_agents_md.py"
- ".github/workflows/docs-drift.yml"
- "AGENTS.md"
- "CLAUDE.md"
- "CONVENTIONS.md"
- ".goosehints"
- "README.md"
- "CONTRIBUTING.md"
concurrency:
group: docs-drift-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
drift-check:
name: Run drift check
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
pull-requests: write
steps:
- name: Harden runner (audit mode)
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.13"
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
enable-cache: true
- name: Install bernstein for agents-md verify
run: uv sync --no-dev --frozen
continue-on-error: true
- name: Run docs drift checker
id: drift
run: |
set +e
python scripts/check_docs_drift.py > drift-report.md
rc=$?
echo "report_rc=${rc}" >> "$GITHUB_OUTPUT"
# Re-run in JSON form for the clean-flag decision.
python scripts/check_docs_drift.py --json > drift-report.json
# Extract the top-level "clean" boolean so later steps can branch.
clean=$(python -c "import json,sys; print(json.load(open('drift-report.json')).get('clean', False))")
echo "clean=${clean}" >> "$GITHUB_OUTPUT"
cat drift-report.md
shell: bash
- name: Upload drift report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: docs-drift-report
path: |
drift-report.md
drift-report.json
retention-days: 14
- name: Comment drift report on the pull request
if: github.event_name == 'pull_request' && steps.drift.outputs.clean != 'True'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const fs = require('fs');
const body = fs.readFileSync('drift-report.md', 'utf8');
const tag = '<!-- docs-drift-report -->';
const issue_number = context.payload.pull_request.number;
const { owner, repo } = context.repo;
const comments = await github.paginate(github.rest.issues.listComments, {
owner, repo, issue_number, per_page: 100,
});
const existing = comments.find(c => c.body && c.body.includes(tag));
const payload = `${tag}\n${body}`;
if (existing) {
await github.rest.issues.updateComment({
owner, repo, comment_id: existing.id, body: payload,
});
} else {
await github.rest.issues.createComment({
owner, repo, issue_number, body: payload,
});
}
- name: Fail the gate on main-branch drift
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: |
python scripts/check_docs_drift.py --strict
docs-data-freshness:
# Advisory check: flags time-stamped metric lines (stars, downloads,
# dated qualifiers) older than 30 days as a soft warning. On push to
# main, markers older than 60 days fail this job. This job is NOT in
# the canary list of required checks: time-stamped metrics drift
# between scheduled refreshes and the gate catches them automatically.
name: Data freshness (advisory)
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
steps:
- name: Harden runner (audit mode)
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.13"
- name: Run data-freshness check (soft on PR, strict on push to main)
run: |
set -e
if [ "${GITHUB_EVENT_NAME}" = "push" ] && [ "${GITHUB_REF}" = "refs/heads/main" ]; then
python scripts/check_data_freshness.py --strict
else
python scripts/check_data_freshness.py
fi
shell: bash