Skip to content

Auto-stamp App + Action

The auto-stamp tooling is the bridge between PR approval and the regulated audit record. When a PR that touched regulatory-docs/**/*.sdoc is merged to main, the auto-stamp Action:

  1. Reads who approved the PR (via the GitHub API)
  2. Verifies the approver matches .github/CODEOWNERS for the touched paths
  3. Computes the SHA-256 fingerprint of each touched requirement’s reviewable content
  4. Writes REVIEWED_HASH + REVIEWED_BY into the .sdoc files
  5. Pushes the stamping commit back to main

The push to main uses a dedicated GitHub App identity — bioflow-autostamp for this repo — added to the branch-protection bypass list. No other workflow has that permission.

This is the mechanism that closes the regulated review trail: every stamped REVIEWED_HASH is cryptographic evidence that this exact content was approved by this exact reviewer at this exact time.

Why we chose this design (Option 1 + dedicated GitHub App)

Section titled “Why we chose this design (Option 1 + dedicated GitHub App)”

Three approaches were considered. Their full trade-off discussion is in the Auto-stamp App setup playbook — short version:

  • Option 1: post-merge auto-stamp pushed directly to main — clean atomic record, but requires push permission to a protected main. Solved by giving a dedicated, narrowly-scoped App that permission. This is what we built.
  • Option 2: stamp on approval, push to PR branch — no bypass needed, but our existing dismiss-stale-on-new-commits rule would dismiss the approval, requiring the reviewer to approve twice per regulated PR.
  • Option 3: merge-queue stamping — uses GitHub’s merge queue. Boss approves once, no double approval. But “Require merge queue” applies to every PR targeting main, adding ~13 min per merge for the whole team — the cost lands on PRs that don’t touch regulatory-docs/.

Option 1 won because it imposes friction only on regulated PRs, gives the cleanest audit semantics, and the bypass-scope concern is fully addressed by the dedicated-App pattern (only bioflow-autostamp can push to main, not every workflow).

  • Python implementation: tools/auto_stamp/
    • main.py — CLI entry point
    • stamper.py — reads .sdoc files, computes hashes (re-using the post-processor’s _compute_content_hash), writes back
    • pr_metadata.pygh api wrappers for fetching approvers + changed files
    • codeowners.py — CODEOWNERS parser + path-glob matcher
    • tests/test_main_end_to_end.py (full chain) + test_pr_metadata.py (review-payload distillation)
  • Workflow: .github/workflows/auto-stamp.yml — runs on pull_request: closed, paths-filtered to regulatory-docs/**/*.sdoc
  • App identity: bioflow-autostamp (created in the Corona-Project-Life org). See the setup playbook for the exact creation steps and field values used.

The workflow runs automatically when a regulated PR merges. Nothing manual.

The workflow is also workflow_dispatch-triggerable. Use this to retroactively stamp a past PR or to retry after a failed automatic run:

  1. Go to Actions → Auto-stamp REVIEWED_HASH → Run workflow
  2. Enter the PR number to stamp
  3. Click Run workflow

The Action will fetch that PR’s approvers, validate them against CODEOWNERS, and stamp the current state of any .sdoc files the PR touched. Only use this when you understand exactly what content the stamping will record.

Run the script against the live repo with fixture metadata (no GitHub API call):

Terminal window
uv run python -m tools.auto_stamp.main \
--pr 42 \
--mock-approver "@DougYoungberg" \
--mock-changed-files regulatory-docs/10_system.sdoc regulatory-docs/11_srs.sdoc regulatory-docs/20_architecture.sdoc regulatory-docs/31_integration_tests.sdoc \
--dry-run

(--mock-changed-files accepts any subset of touched regulatory-docs/**/*.sdoc files (the three top-level spec tiers and any test spec under regulatory-docs/); the example above exercises all three spec tiers plus an integration-test spec.)

--dry-run reads metadata, validates the approver, and prints what would be stamped — but does not modify any files. Drop --dry-run to actually write.

Run the unit tests:

Terminal window
uv run pytest tools/auto_stamp/tests/ -p no:visiontrace

(-p no:visiontrace silences VisionTrace’s autouse screen-recording fixture, which is irrelevant here.)

  • The auto-stamp tool is regulated software in its own right — a bug here directly produces wrong audit evidence
  • CODEOWNERS-gated path: tools/auto_stamp/** requires qualified review for any change
  • The hash function is shared with the post-processor (imported directly from tools/post_processor/rtm.py) — keeping them in lockstep is mandatory; never re-implement the hash here
  • Tool qualification: a CSA package for the auto-stamp Action is on the regulated roadmap (alongside the post-processor’s qualification). Outlined in the skill file. Status: pending.

Auto-stamp is internal; this page is its canonical documentation. See also: