agentleFS
docxologydocxology/template/.github/workflows/AGENTS.md

template / workflows

AGENTS.md20 starsChanged 2 months agoApache-2.0View on GitHub

ci.yml runs on main pushes, pull requests and manual dispatch. It uses Linux and Python 3.14: lint/types and public data/security guards, pipeline smoke, a standalone wheel build and focused behavioral tests for every public template, and the required CI Gate. .github/project-smoke.json names the actual tests; the smoke runner refuses missing projects, empty selections and escaping paths. These are functional checks, with no full-suite coverage or native acceptance claim. The former cross-version/full-suite matrix remains in hardening.yml, invoked manually. platform-required-acceptance.yml is also…

We split this AGENTS.md into the rules it gives an agent

2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Enforced policy: no configured prohibited mock-framework imports/calls (MagicMock, mocker.patch, unittest.mock, and related lexical forms) …

    line 138
  2. Very specific:

    Never checks out or executes PR HEAD code — only reads metadata and calls the GitHub API — so the elevated pull_request_target trigger does …

    line 311

≈ “Common” is an estimate: at least 1 in 5 of the 36,368 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

Fast functional CI

ci.yml runs on main pushes, pull requests and manual dispatch. It uses Linux and Python 3.14: lint/types and public data/security guards, pipeline smoke, a standalone wheel build and focused behavioral tests for every public template, and the required CI Gate. .github/project-smoke.json names the actual tests; the smoke runner refuses missing projects, empty selections and escaping paths. These are functional checks, with no full-suite coverage or native acceptance claim.

The former cross-version/full-suite matrix remains in hardening.yml, invoked manually. platform-required-acceptance.yml is also manual-only; its original custody requirements remain mandatory for formal release acceptance. Further hardening choices and the local commands are in docs/development/ci.md.

CI/CD Workflows

Overview

The workflows/ directory contains GitHub Actions workflows that automate the continuous integration and delivery pipeline for the Research Project Template. These workflows ensure code quality, test reliability, and compatibility across environments.

Directory Structure

flowchart LR
    W[.github/workflows/]
    W --> META[AGENTS.md · README.md]
    W --> FAST[ci.yml<br/>Linux/Python 3.14 functional checks · CI Gate]
    W --> CI[hardening.yml<br/>20 jobs · 2 conditional via detect outputs<br/>manual-only lanes: test-infra-slow, public-matrix-receipt]
    W --> STALE[stale.yml<br/>Auto-label/close stale issues/PRs]
    W --> REL[release.yml<br/>Create GitHub Releases on version tags]
    W --> REQUIRED[platform-required-acceptance.yml<br/>Original observations + strict candidate collector]
    W --> DA[dependabot-automerge.yml<br/>Auto-merge safe Dependabot PRs]

    classDef d fill:#0f172a,stroke:#0f172a,color:#fff
    classDef code fill:#1e3a8a,stroke:#0f172a,color:#fff
    classDef doc fill:#0f766e,stroke:#0f172a,color:#fff
    class W d
    class FAST,CI,STALE,REL,REQUIRED code
    class META doc

Optional exhaustive hardening (hardening.yml)

Triggers

workflow_dispatch only. Each manual run uses its unique run ID and preserves its evidence independently. This lane is not a requirement for ordinary main integration. Its aggregate check is named Hardening Gate.

Global env: UV_FROZEN=true, MPLBACKEND=Agg (non-interactive matplotlib backend).

Job Graph

health, validate, security, and docs-lint run independently alongside lint; each uses its own checkout and setup. setup-hook-windows-smoke depends on verify-no-mocks and detect and is skipped unless needs.detect.outputs.setup_hook == 'true'. The test jobs run through the independent verify-no-mocks subtree; test-infra also consumes detect-projects. An individual job can pass when lint fails. The aggregate ci-gate must still fail when a required job fails or is unexpectedly skipped. This graph describes hardening.yml; workflow checks and review verify its current dependencies and aggregate policy.

flowchart TB
    DET[detect<br/>optional-project outputs]
    DETP[detect-projects<br/>validated capability matrix output]
    ACTLINT[actionlint<br/>lints workflow YAML · standalone]
    LINT[lint]
    HEALTH[health<br/>unified JSON artefact]
    VNM[verify-no-mocks<br/>parallel with lint · no needs:]
    VAL[validate]
    SEC[security]
    DL[docs-lint<br/>mermaid + cross-links + consistency<br/>installs mmdc + chrome-headless-shell]
    VNM --> SHW[setup-hook-windows-smoke<br/>skipped if no setup_hook.py]
    DETP -.->|infra_matrix output| TI
    VNM --> TI[test-infra<br/>dynamic matrix from detect-projects<br/>manual: ubuntu × 3.12-3.14 + macOS × 3.14<br/>full supported matrix · four complete shards per environment]
    TI --> IC[coverage-infra<br/>complete 3.14 Linux union ≥60%]
    VNM --> TR[test-regression<br/>claim-binding pins · tests/regression/]
    VNM --> TP[test-project<br/>capability manifest roster × canonical Python versions<br/>stage_01_test.py --project per cell]
    VNM --> FL[fep-lean<br/>ubuntu-only · skipped if no lean-toolchain]
    DET --> SHW
    DET --> FL
    DETP --> TP
    PERF[performance<br/>no needs · CI-FAST-PERF-1]

    classDef gate fill:#1e3a8a,stroke:#0f172a,color:#fff
    classDef matrix fill:#0f766e,stroke:#0f172a,color:#fff
    classDef terminal fill:#7c2d12,stroke:#0f172a,color:#fff
    classDef info fill:#334155,stroke:#0f172a,color:#fff
    class DET,DETP,LINT,VNM gate
    class TI,TR,TP,FL,SHW matrix
    class VAL,SEC,DL,PERF,ACTLINT terminal
    class HEALTH info

Shared setup — local composite actions

Jobs that need Python share one local composite action, .github/actions/setup-python-env, which runs astral-sh/setup-uv (with uv.lock cache) + actions/setup-python. The pinned action SHAs and cache config live there once instead of being copy-pasted per job. Usage (checkout must come first — a local action's files only exist after checkout):

steps:
  - uses: actions/checkout@<sha>
  - uses: ./.github/actions/setup-python-env       # defaults to Python 3.14
    # with: { python-version: ${{ matrix.python-version }} }  # matrix jobs only
  - run: uv sync                                    # per-job groups stay explicit

detect and actionlint are checkout-only and do not use it. Each job keeps its own uv sync … line so optional groups (rendering/monitoring/discopy) remain visible per job. When bumping a setup action's SHA, edit the composite action — not each job.

The health and docs-lint jobs additionally share .github/actions/setup-docs-lint, which provisions the pinned Node runtime/cache plus real mmdc and chrome-headless-shell. This keeps unified health's docs-lint constituent behaviorally equivalent to the dedicated documentation job.

Job Details

1. Lint & Type Check (lint)

  • Runner: ubuntu-latest / Python 3.14
  • Tools: uv run ruff check, uv run ruff format --check, uv run mypy, uv run python -m infrastructure.skills check-all-exports, uv run python scripts/audit/check_template_drift.py --strict
  • Scope: Ruff uses public lint paths from infrastructure.project.public_scope lint-paths; mypy uses its narrower source-paths output.

2. Static Health Report (health)

  • Runner: ubuntu-latest / Python 3.14
  • Depends on: nothing; the job performs its own checkout and setup alongside lint. A red static gate turns this job red and blocks ci-gate; this page does not certify hosted-runner behavior beyond that.
  • Purpose: Runs uv run python -m infrastructure.core.health --json --quiet → health-report.json; every represented static gate blocks, while behavioral and platform matrices remain separate jobs; a gate exiting non-zero must turn the job red, and warnings alone never satisfy it. Negative control: when any represented static gate fails, infrastructure.core.health exits non-zero and blocks this job rather than reporting green alongside a failure. A negative control backs this contract: deliberately breaking any represented static check locally flips the aggregate health report away from healthy status, which blocks the job.
    • Negative control: removing or weakening a represented static gate in infrastructure/core/health.py must make the health job fail on the next run — a green report with a missing gate is invalid.

3. Verify No Mocks Policy (verify-no-mocks)

  • Runner: ubuntu-latest / Python 3.14
  • Script: scripts/audit/verify_no_mocks.py (repository root)
  • Enforced policy: no configured prohibited mock-framework imports/calls (MagicMock, mocker.patch, unittest.mock, and related lexical forms) in test files.
  • Boundary: --inventory separately classifies permitted environment isolation and semantic dependency replacement. CI enforces a zero ceiling for dependency replacements; environment isolation remains permitted.

3b. Setup hook — Windows smoke (setup-hook-windows-smoke)

  • Runner: windows-latest / Python 3.14
  • Depends on: verify-no-mocks
  • Conditional: if: needs.detect.outputs.setup_hook == 'true' — no-op skip when no project ships infrastructure.project.setup_hook. The detect job computes this because job-level hashFiles() is invalid in GitHub Actions.
  • Step: uv run pytest tests/infra_tests/project/test_setup_hook.py with PYTHONUTF8=1

4. Infrastructure Tests (test-infra)

  • Pinned source setup: test-infra and coverage-infra both initialize the direct submodule declared by the actual Root gitlink and .gitmodules using the pinned checkout action's submodules: true. This checks out the committed kmyth object; the declaration's branch is not used to advance it. Initialization is an explicit network-capable setup boundary before Python setup and source observation. Tests subsequently clone this actual local checkout without network. Both jobs use persist-credentials: false, so setup credentials are removed before test or merge code runs. The merge runner receives the same complete source bytes as the coverage workers; missing pins remain failures, with no fixture fabrication or skip. The canonical workflow guard in tests/infra_tests/core/test_ci_infra_partition.py checks both setup declarations against the actual native Git index and public submodule declaration. test-project, test-infra-slow, and public-matrix-receipt use the same pinned, credential-free checkout contract before their genuine standalone export controls.
  • Sync: uv sync --locked --group public-exemplars --group installed-build. Genuine wheel/sdist controls use the prepared, locked build backend.
  • Offline warm: a scratch uv sync --frozen against the selected interpreter re-populates the uv cache with every locked default-group wheel (setup-uv prunes registry wheels from the saved cache), so infra tests that build fresh environments with uv sync --locked --offline do not depend on a cold or pruned cache. The scratch environment is deleted.
  • Document tools: Both platforms invoke setup-acceptance-documents once. It verifies exact pinned Pandoc/crossref/font archives, prepares the complete TeX and native-reader package union, and probes the selected executables. Linux installs poppler-utils; macOS installs poppler. Both lanes directly check pdftoppm and pdffonts before the actual PDF controls. Package caches cannot certify preparation or acceptance.
  • Matrix: Every existing environment is retained: Linux Python 3.12–3.14 and macOS Python 3.14. The source-declared ci_infra_partition.py emits four complete module shards per environment (16 cells). The four measured C4 families are assigned distinct shards; every other current or future collected module receives a stable SHA-256 assignment. No test is marked slow or removed by partitioning.
  • Selection: ci_infra_shard_plugin partitions actual pytest collection after the unchanged ordinary marker expression. Each selected case belongs to exactly one shard; empty/duplicate/noncanonical inventory, worker disagreement and incomplete actual completion fail. The plugin is explicitly loaded for this invocation, so nested pytest jobs retain their own selection.
  • Diagnostics: On the xdist controller the plugin also keeps a bounded, diagnostics-only record (output/readiness/ordinary-infra-ci/diagnostics/shard-N.json) of active cases, recent events, first failures and worker loss, labeled by declared public test family and member hash only. Every shard uploads it with if: always() as infra-diagnostics-<os>-<python>-<shard>; the manual test-infra-slow job loads the plugin with --infra-ci-observer-only slow to retain shard-slow.json as infra-diagnostics-slow without partition or selection admission. These records identify where a crashed or cancelled job was, and cannot replace a selection receipt or authorize coverage.
  • Budgets: The job is 90 minutes, pytest remains --timeout=120, and every existing per-case timeout override remains effective. Linux retains -n auto, macOS retains -n 2, and both use --dist loadscope. Faster completion is a hypothesis until fresh hosted timings establish it; additional jobs repeat preparation and may increase total runner minutes.
  • Coverage: Only the four Python 3.14/Linux shards instrument execution. Per-shard thresholds are replaced by the required coverage-infra complete-union gate at the same ≥60% floor. The gate refuses missing/extra/duplicate/stale/failed selection records, incomplete case unions and changed coverage bytes, then merges genuine branch measurements in memory and writes confined JSON/XML. Codecov upload remains nonblocking after this required local threshold passes.
  • Receipt scope: Ordinary selection records bind infrastructure/scripts/infra tests/CI configuration source bytes. They do not replace full public source custody, installed-wheel, live, platform or release acceptance; missing Root release policy remains blocked.
  • MathJax live viewport: The manual hardening browser spec runs once on shard 0 of Python 3.14/Linux. Its existing tool provisioning, completed-typesetting checks and failure policy remain unchanged.

For an unpartitioned local check, the existing full pytest tests/infra_tests/ command remains supported without this explicit plugin. An exact shard invocation requires a fresh owned checkout and uses -p infrastructure.core.testing.ci_infra_shard_plugin --infra-ci-shard N with the workflow's marker expression; the slow lane's observer-only form is -p infrastructure.core.testing.ci_infra_shard_plugin --infra-ci-observer-only slow -m slow. The selection receipt is local execution state, not a cache or resume authorization.

4b. Regression Tier — claim-binding pins (test-regression)

  • Depends on: verify-no-mocks, timeout-minutes: 20, ubuntu-only.
  • Sync: uv sync --group public-exemplars.
  • What it runs: uv run pytest tests/regression/ -q --no-cov --timeout=120 --junitxml=<fresh job-local report>, serial (no -n auto) — see docs/maintenance/regression-testing.md for why (exemplars ship colliding top-level src packages resolved via per-project aliases + temporary sys.meta_path finders whose isolation is collection-order-sensitive).
  • Collection contract: the ordinary run must exit zero, including successful collection. "Assert regression tier is not empty" then reads that run's fresh JUnit report and requires at least 3 actual case entries with no failures or errors. Missing/malformed reports and empty or undersized suites block. This replaces a second collection-only invocation while keeping the original selector and three-case minimum.

4c. Integration Tier — repository wiring (test-integration)

  • Depends on: verify-no-mocks, timeout-minutes: 20, ubuntu-only.
  • Sync: uv sync --group public-exemplars.
  • What it runs: uv run pytest tests/integration/ -q --no-cov --timeout=120 --junitxml=<fresh job-local report>, serial.
  • Collection contract: the same successful-run JUnit census requires at least 3 case entries and no failures or errors. Collection errors retain pytest's nonzero exit; missing/malformed, empty, or undersized reports block. The shell and pipeline suite selector stays unchanged.

5. Project Tests (test-project)

  • Sync: uv sync --locked --group public-exemplars --group installed-build — the deterministic dependency union includes DisCoPy, monitoring, scientific, LLM-client, and PPTX dependencies plus the prepared backend for offline genuine-wheel controls. Hypothesis comes from the dev group (see root pyproject.toml [dependency-groups] and default-groups).
  • Standalone preparation: the Autoresearch cell separately exports the root installed-build group and its own exact nonlocal runtime lock, both with hashes, and installs each into a disposable environment with uv pip sync --no-config --no-build --require-hashes before tests. The lockfile uv sync above fetches wheels by locked URL and does not record the registry entries that the offline genuine-wheel acceptance (uv pip sync --offline) resolves from, so this explicit setup is what fills the cache for it; the root and exemplar locks retain their independent versions.
  • Matrix: Per-project split — the detect-projects job runs scripts/gates/public_capabilities.py --ci-matrix-json, which validates unique normalized package identities, full-minor Python compatibility, source/test syntax, format declarations, compiled/confined direct hydration, analysis declarations, reason-bearing skips, exact roster membership, and exact matrix parity before emitting the canonical project × Python include list. The current source of truth yields 25 exemplars × Python 3.12/3.13/3.14 = 75 matrix cells on ubuntu-latest; no project or Python literal is duplicated in workflow YAML. Both matrix jobs set UV_PYTHON and assert the selected runtime minor so the repository .python-version cannot override a matrix cell. Job timeout-minutes: 135; its direct Stage-01 invocation owns one 115-minute generic-or-declared project budget, leaving 20 minutes for setup, descendant cleanup, and uploads. The full pipeline's separate 120-minute stage wrapper is not present on this hosted direct path. These limits provide execution capacity; they do not show that a project suite passed or emitted valid evidence.
  • Coverage threshold: Each job enforces that project's own ≥ 90% floor on its src/ (per CLAUDE.md). There is no longer a combined-union run or --cov-append — every project is isolated in its own job, which also removes the old code_project/fep_lean conftest plugin-name collision.
  • Coverage files: project-local .coverage.project for the generic pytest path or .coverage for a declared structured verifier; both are isolated, cleaned before the run, and independently produce the same project-local coverage_project.json.
  • Scope: scripts/pipeline/stage_01_test.py --project <name> --project-only --include-slow (one invocation per matrix cell). The workflow uploads the resulting project-local JSON directly; it does not synthesize a separate XML report. Rotating local projects are not part of this public-repo gate; dedicated project jobs own their own toolchains.
  • External render tools: every lane unconditionally invokes setup-acceptance-documents for exact pinned Pandoc/crossref preparation. EDA selects native because its ordinary tests directly require XeLaTeX and embedded JuliaMono faces; other ordinary project cells select converter. Infrastructure and all genuine acceptance callers retain the default native package/font preparation. Test selections, coverage floors and required native acceptance remain unchanged; no runtime or cost improvement is established until genuine execution is measured.
  • Codecov upload: On Python 3.14 / ubuntu-latest only; upload failures do not fail CI

6. fep_lean — real Open Gauss + Lake (fep-lean)

  • Conditional: Job is skipped unless projects/fep_lean/lean/lean-toolchain exists and the detect job emits fep_lean == 'true'. When fep_lean lives under projects/working/, detect reports false and the job is skipped. Promote with mv projects/working/fep_lean projects/fep_lean to activate.
  • Runner: ubuntu-latest / Python 3.14 only; job timeout-minutes: 60
  • Depends on: verify-no-mocks
  • Working directory (when present): projects/fep_lean for pytest; projects/fep_lean/lean for Lake warm-up
  • Toolchain: SHA-pinned elan installer (with checksum verification) + pinned lean-toolchain, lake build warm-up
  • Open Gauss: clone math-inc/OpenGauss, ./scripts/install.sh --plain --noninteractive --skip-system-packages, gauss doctor
  • Tests: uv run pytest tests/ --timeout=1200 --cov=src --cov-fail-under=89 with COVERAGE_FILE: ../../.coverage.fep_lean
  • Scaling: Full catalogue × Lean is expensive; if runtime grows past the job budget, split slow integration tests behind a pytest marker or shard topics in a follow-up workflow.

7. Validate Manuscripts (validate)

  • Runner: ubuntu-latest / Python 3.14
  • Steps:
    1. infrastructure.validation.cli markdown projects/*/manuscript/ — validates all active project manuscripts
    2. scripts/docgen/api_reference.py --check — API reference drift gate
    3. Dynamic project import check — imports the public project source paths from infrastructure.project.public_scope

8. Security Scan (security)

  • Runner: ubuntu-latest / Python 3.14
  • pip-audit: blocking; audits the root all-groups/all-extras export and every canonical public-exemplar all-extras export, builds --ignore-vuln args from .github/pip-audit-ignore.txt, and retries each export up to 3 times with backoff on failure (transient OSV/network issues)
  • bandit: bandit -c bandit.yaml -r -ll, covers infrastructure/, scripts/, projects/; path exclusions are in bandit.yaml (exclude_dirs, including archive/WIP roots and .venv / site-packages so local trees are not scanned)

9. Documentation Lint (docs-lint)

  • Runner: ubuntu-latest / Python 3.14 / Node 20
  • Depends on: nothing; the job performs its own checkout and setup alongside lint.
  • Timeout: 15 minutes
  • External tools (real, not mocked):
    • mmdc (mermaid-cli) — pinned in the root package.json; run npm ci
    • chrome-headless-shell — npx --no-install puppeteer browsers install chrome-headless-shell, exported via CHROME_EXECUTABLE_PATH
  • Linters (thin orchestrator scripts/audit/lint_docs.py):
    1. Mermaid — every fenced ```mermaid block in docs/, infrastructure/, .github/, scripts/, and root *.md is rendered with the real mmdc binary. Failure exits non-zero.
    2. Cross-links — every relative Markdown link must resolve on disk; fenced and inline-code spans are skipped.
    3. Consistency — N Python (sub)packages claims must match the live count under infrastructure/; rotating project names (fep_lean, cogant, …) must be conditionally framed in long-lived docs. Skip lists narrow the scan — they do not certify the excluded trees; anything outside the skips still fails the lint job.
    4. Doc pairs — permanent-template content folders must carry paired AGENTS.md and README.md; generated/local paths and rotating projects are excluded.
  • Escape hatch: append <!-- noqa: docs-lint --> to a Markdown line to suppress consistency or broken-link warnings on that line. Negative control: adding a deliberately broken relative link to a tracked doc makes uv run python scripts/audit/lint_docs.py exit non-zero — the run fails when any unresolved cross-link is reported. This skip list bounds what the linter checks: it scans tracked documentation only, and checking skip rules does not prove correctness of excluded generated trees.
  • Scope guarantees: the linter scans only tracked Markdown outside generated/local paths such as output/, .venv/, .claude/, projects/archive/, projects/working/, htmlcov/, and node_modules/; inside those trees it enforces nothing. Known-wrong input: an unlisted build tree such as a fresh dist/ holding broken links is NOT skipped by these guarantees — the exclusion list is closed, and excluding a new path requires an explicit entry in infrastructure/validation/docs/scan_scope.py.
  • Module: infrastructure/validation/docs/ — mermaid_lint.py, cross_link_lint.py, consistency_lint.py, doc_pair_lint.py.

10. Performance Check (performance)

  • Runner: ubuntu-latest / Python 3.14
  • Depends on: nothing (CI-FAST-PERF-1 — the job consumes no upstream artifacts, so no needs:; ci-gate still requires it). It therefore runs in the first wave instead of after the slowest project cell.
  • Threshold: each infrastructure.core or public project src cold import from infrastructure.project.public_scope must complete in ≤ 5 seconds
  • Per-module timing and the roster-dependent total are reported to stdout for trend analysis

Quality Gates

GateThresholdEnforced by
Ruff lintingzero violationslint job
Ruff formattingzero diffslint job
mypy strict gatezero errors across the generated public source scopelint job
Mock-framework lexical gatezero prohibited imports/callsverify-no-mocks job
Public capability parityexact roster/matrix; compatible Python floors; valid package/render/hydration/analysis declarationsdetect-projects + unified health
Infrastructure coverage≥ 60%coverage-infra complete-union job
Per-project coverage (standalone)≥ 90%each project's own pytest gate
Combined-union public-project coverage≥ 75%test-project job (DEFAULT_FAIL_UNDER)
fep_lean coverage≥ 89%fep-lean job (skipped if projects/fep_lean/lean/lean-toolchain absent)
pip-auditno unignored vulnerabilitiessecurity job
Bandit MEDIUM+ (bandit.yaml)zero findingssecurity job
Import time≤ 5 seconds totalperformance job

Stale Workflow (stale.yml)

Runs daily at 01:00 UTC using actions/stale@v10.3.0.

ItemStale afterClosed after
Issues60 days inactive+ 14 days
Pull Requests30 days inactive+ 14 days

Exempt labels: pinned, security, in-progress, blocked, do-not-close


Release Workflow (release.yml)

Triggers on v*.*.* tag push or workflow_dispatch (with tag input). Both triggers serialize by the selected tag and preserve in-flight publication; a manual dispatch from a different branch cannot race the same tag push.

  1. Resolves the requested tag before checkout, initializes its pinned submodules, and proves HEAD equals the dereferenced tag commit
  2. Prepares supported interpreters, the locked release environment and identical acceptance fixture inputs; audits pristine published exemplars before the installed handoff
  3. For root 4+, requires the exact successful hosted run ID, platform-required-acceptance artifact ID and aggregate receipt SHA256; authenticates the same-repository exact-revision run and bounded artifact, then uses an independently installed current reader to authenticate every candidate requirement, the complete retained installed matrix and its exact admitted wheel/receipt. Tag pushes without that explicit handoff stop
  4. Runs the tagged-SHA no-mocks and bounded pipeline-smoke gates, root release contract and fail-closed public capability manifest
  5. Earlier major tags retain the clean-export, install and import-smoke matrix on Python 3.12/3.13/3.14. Root 4+ already authenticated its retained complete matrix in step 3. Preparation and acceptance stay distinct
  6. Builds the final source distribution and admits its exact final bytes alongside the wheel already accepted by the installed matrix; the pristine published audit has already passed before derived execution
  7. For root 4+, selects docs/releases/<tag>.md for the actual tag, such as the 4.0.1 candidate notes, and adds accepted-commit, hosted-run and receipt-hash bindings; earlier major tags use the commit-based git-log excerpt
  8. Creates a GitHub Release using softprops/action-gh-release@v3.0.3 with generate_release_notes: false and attaches the admitted distributions, tag-selected overview PNG and byte manifest
  9. Retrieves the published assets and requires exact admitted hashes; auto-marks as pre-release if the tag contains -rc, -beta, or -alpha

The candidate platform-required-acceptance.yml implements six original Root minor/platform units plus common and native observations and a strict independent collector. Only its passed complete exact-source bundle can supply the root 4+ handoff. Implementation presence or a dated version heading is not proof of successful acceptance, integration into main, or publication. Ordinary CI and partial/static results cannot replace it.

The pinned checkout action and release action use the Node 24 JavaScript action runtime. This is separate from the Node 20 document toolchain selected by setup-docs-lint. GitHub-hosted runners satisfy the documented runtime requirement; self-hosted runners must be Actions runner v2.327.1 or newer.

Dependabot Automerge Workflow (dependabot-automerge.yml)

Triggers on pull_request_target (opened, reopened, synchronize, ready_for_review) — but only acts when github.actor == 'dependabot[bot]'.

  1. Fetches Dependabot update metadata via dependabot/fetch-metadata@v3.1.0
  2. Enables GitHub native auto-merge (gh pr merge --auto --squash) for semver-minor and semver-patch updates only; major bumps are left for human review
  3. Never checks out or executes PR HEAD code — only reads metadata and calls the GitHub API — so the elevated pull_request_target trigger does not expose secrets to untrusted code
  4. Auto-merge must also be enabled in repository settings (Settings → General → "Allow auto-merge")

Local CI Simulation

# Reproduce lint locally
uv sync
uv run python -m infrastructure.project.public_scope lint-paths | xargs uv run ruff check
uv run python -m infrastructure.project.public_scope lint-paths | xargs uv run ruff format --check
uv run python -m infrastructure.project.public_scope source-paths | xargs uv run mypy

# Reproduce infrastructure tests locally
COVERAGE_FILE=.coverage.infra uv run pytest tests/infra_tests/ \
  --cov=infrastructure \
  --cov-fail-under=60 \
  -m "not requires_ollama"

# Reproduce project tests locally (matrix job ignores fep_lean). The root
# default groups include the deterministic public-exemplar dependency union.
uv sync
COVERAGE_FILE=.coverage.project uv run python scripts/pipeline/stage_01_test.py --project-only --all-projects --public-projects --non-strict --include-slow
uv run coverage xml -o coverage-project.xml

# fep_lean only — requires gauss, lake, lean on PATH (see that project's tests/AGENTS.md when present)
(cd projects/fep_lean && COVERAGE_FILE=../../.coverage.fep_lean uv run pytest tests/ \
  --timeout=900 \
  --cov=src \
  --cov-fail-under=89 \
  -m "not requires_ollama")

# Reproduce security scan locally (mirror CI — build ignores from file)
IGNORE_ARGS=()
while IFS= read -r raw || [ -n "$raw" ]; do
  [[ "$raw" =~ ^[[:space:]]*# ]] && continue
  line="${raw%%#*}"
  line="$(echo "$line" | xargs)"
  [ -z "$line" ] && continue
  IGNORE_ARGS+=(--ignore-vuln "$line")
done < .github/pip-audit-ignore.txt
AUDIT_DIR="$(mktemp -d /tmp/template-public-audit.XXXXXX)"
uv export --all-groups --all-extras --frozen --no-hashes \
  --no-emit-project --output-file "$AUDIT_DIR/root.txt"
uv run pip-audit --requirement "$AUDIT_DIR/root.txt" \
  --no-deps --disable-pip "${IGNORE_ARGS[@]}"
for project in $(uv run python -m infrastructure.project.public_scope project-names); do
  slug="${project//\//-}"
  uv export --project "projects/$project" --all-extras --frozen --no-hashes \
    --no-emit-project --output-file "$AUDIT_DIR/${slug}.txt"
  uv run pip-audit --requirement "$AUDIT_DIR/${slug}.txt" \
    --no-deps --disable-pip "${IGNORE_ARGS[@]}"
done
uv run bandit -c bandit.yaml -r -ll infrastructure/ scripts/ projects/

Troubleshooting

Linting failures

uv run python -m infrastructure.project.public_scope lint-paths | xargs uv run ruff check --fix
uv run python -m infrastructure.project.public_scope lint-paths | xargs uv run ruff format

Test failures

# Infrastructure
uv run pytest tests/infra_tests/ -v --tb=long -s

# Project tests — prefer the orchestrator (runs one pytest per project; avoids conftest/package collisions):
uv run python scripts/pipeline/stage_01_test.py --project template_code_project

# Advanced / blanket globs — running **all** `projects/*/tests/` in **one** pytest process can fail when multiple projects ship `tests/conftest` packages with identical names; use per-project directories instead.

uv run pytest projects/*/tests/ -v --tb=long -s

# Single test
uv run pytest tests/infra_tests/test_foo.py::TestClass::test_method -s --pdb

Coverage below threshold

# Infrastructure report
COVERAGE_FILE=.coverage.infra uv run pytest tests/infra_tests/ \
  --cov=infrastructure --cov-report=html
open htmlcov/index.html

# Project report — replace SRC_PATH with `projects/<name>/src` from _generated/active_projects.md when benchmarking coverage manually:
COVERAGE_FILE=.coverage.project uv run pytest projects/templates/template_code_project/tests/ \
  --cov=projects/templates/template_code_project/src --cov-report=html
open htmlcov/index.html

Performance check slow

# Profile imports
uv run python -c "
import cProfile, pstats, io
pr = cProfile.Profile()
pr.enable()
import infrastructure.core
pr.disable()
s = io.StringIO()
ps = pstats.Stats(pr, stream=s).sort_stats('cumulative')
ps.print_stats(20)
print(s.getvalue())
"

See Also

The infrastructure partition changes execution placement only. The required coverage-infra job consumes every 3.14/Linux shard, validates their complete disjoint case union and source/data identities, and enforces the unchanged 60% floor. The existing ci-gate complete-job policy includes this job; an unsuccessful or skipped merge prevents optional exhaustive hardening acceptance. Root 4 release evidence remains separately required.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.