Playbook: Git identities & role responsibilities (commit → PR → review → merge → deploy)
Status: active · Owner: p24-infra · Review: every 90 days or on any identity change
Scope: every repo operated from p24-infra sessions (p24-infra, et-operational-platform, brandpilot,
Art-Agency, radekkonarski-personal-brand, gmail-tools, whatsup-android-chat-puller) + GitLab pinbox24/*.
Single source of truth for “which identity performs which Git action”. Other docs link here and must not restate the matrix. This playbook does not restate branch/commit format, review-pipeline mechanics, or per-host provisioning detail — it links to the canonical home of each (see §13).
Trigger — read this when you need to answer any of: who commits / who opens the PR / who reviews / who approves / who merges / who (really) deploys, for a given role and repo; or you are debugging a self-approval collision, a Vercel author-block, or a stuck review.
1. Identity registry
One row per identity. Credential sources are named by key/file NAME only — never a value.
| Identity | Kind | Runs on | GitHub/GitLab login | Git author (name / email) | Credential source | Rotation |
|---|---|---|---|---|---|---|
radieu | human | lap2 (active interactive host), windows-dev (dormant until ~2026-10-15, then 2nd interactive host) | radieu | Radek Konarski / radieu@gmail.com | gh keyring | — |
AI-Dev-BMS4-1 | worker bot | bms-4 OS acct claude-runner | AI-Dev-BMS4-1 | AI-Dev-BMS4-1 / ai-dev-bms4-1@zintegrowana.online (repo-local since #7614) [D1] [VERIFY] | gh device flow + App-2109526 clone token | 180d |
ai-dev-bms4-2 | worker bot | bms-4 OS acct claude-runner-2 | ai-dev-bms4-2 | ai-dev-bms4-2 / ai-dev-bms4-2@zintegrowana.online (repo-local since #7614) [D1] | same | 180d |
AI-Dev-IO1 | worker bot | vps-i1 OS acct claude-runner | AI-Dev-IO1 | AI-Dev-IO1 / ai-dev-io1@zintegrowana.online (repo-local since #7614) [D1] [VERIFY] | same | 180d |
ai-dev-windev-1 | bot (interactive/automation identity) | windows-dev (dormant), lap2 [D6] | ai-dev-windev-1 | not set globally — machine git stays radieu; per-repo/per-command only | gh device flow | 180d |
p24-reviewer | GitHub App — review-only | review-pr worker | App 5208530 / inst. 168439358 | n/a (reviews, never commits) | github-reviewer-app.env.sops | regenerate private key (Tier 3) |
p24-infra-admin (App 2109526) | GitHub App — broad | CI, worker clone, gh secret set, n8n, counting PR approve [D5] | App / inst. 142989418 | n/a | GH Secrets / SOPS App-key entries | key rotate |
p24-n8n-issues [VERIFY] | GitHub App — n8n issues | n8n workflows | App | n/a | n8n-bms4.env.sops (N8N_GITHUB_APP_*) | key rotate |
GITLAB_ADMIN_PAT | GitLab PAT (group Owner) | bms-4 infra-task worker | group pinbox24 Owner | n/a | pinbox24-gitlab.env.sops (narrow bms-4 copy, #4796) | gitlab-token-rotation |
| CI token | CI | GH Actions | github-actions / App 2109526 | n/a | GH Secrets | — |
| deploy SSH key | key | CI → servers | root | n/a | VPS_SSH_PRIVATE_KEY | per rotation matrix |
| Vercel / Cloudflare deploy tokens | provider tokens | CI | n/a | n/a | GH Secrets / SOPS | per rotation matrix |
[VERIFY] = asserted but not yet confirmed against an authoritative source (a live git log on the
named host, or an App/registry listing). p24-n8n-issues currently appears only in
docs/secrets-rotation-log.md (App added 2026-10-08, #7481); the AI-Dev-BMS4-1 / AI-Dev-IO1 author
rows await a live git log observation on their own hosts (the ai-dev-bms4-2 row is observed here).
Git author, post-#7614 ([D1]). On main, squash-merge commits are authored by the
PR-opening bot with a @zintegrowana.online address (verified 2026-10-08: PR #7604 squash commit
author ai-dev-bms4-2 <ai-dev-bms4-2@zintegrowana.online>, committer GitHub, signature verified).
Worker branch commits were previously authored radieu <radieu@gmail.com>; #7613 / PR #7614
(merged 2026-10-08) fixed this. spawn-worker.sh now writes a repo-local identity on the
per-issue clone: user.name = the worker’s GitHub login, user.email =
<login-lowercased>@zintegrowana.online (the D1 target). [VERIFY] on the next worker PR with
git log --format='%an|%ae|%cn|%G?' — this doc’s own branch commit is authored
ai-dev-bms4-2 <ai-dev-bms4-2@zintegrowana.online>, confirming the mechanism is live in this clone.
Worker-to-OS-account and auth-method detail is owned by
worker-gh-auth-standard.md §Worker registry — not restated here.
2. Role × action matrix
Rows = session roles (see CLAUDE.md §Role Enforcement) + human-owner. A cell names the identity used,
or ✗ if the action is forbidden for that role. Enforcement level per repo is in §3.
| Action | dev-coder | dev-reviewer | dev-tester | sys-admin | secret-manager | human-owner |
|---|---|---|---|---|---|---|
| Commit to feature branch | worker bot | ✗ | worker bot (tests) | worker bot | worker bot (SOPS files) | radieu |
| Push branch | worker bot | ✗ | worker bot | worker bot | worker bot | radieu |
| Open PR | worker bot | ✗ | worker bot | worker bot | worker bot | radieu |
| Post review comments | ✗ | p24-reviewer | ✗ | ✗ | ✗ | radieu |
| Approve | ✗ | verdict: p24-reviewer · counting approve: App 2109526 | ✗ | ✗ | ✗ | radieu [D4] |
Merge to main (p24-infra) | ✗ | review-pr worker [D2] | ✗ | ✗ | ✗ | radieu (--admin) |
| Merge to integration branch (app repos) | ✗ | review-pr worker [D2] | ✗ | ✗ | ✗ | radieu |
| Tag / release | ✗ | ✗ | ✗ | worker/CI | ✗ | radieu |
| Deploy (CI-triggered by merge) | — automatic (see §8) | — | — | — | — | — |
Deploy (manual, # PLAYBOOK:-annotated) | ✗ | ✗ | ✗ | sys-admin (SSH) | ✗ | radieu |
| SOPS write / rotate | ✗ | ✗ | ✗ | ✗ (read key NAMES only) | secret-manager | ✗ |
GitLab MR merge (pinbox24/*) | ✗ | ✗ | ✗ | infra-task worker (+ coupled-deploy check) | ✗ | radieu |
Notes:
- Approval is dual-identity (decided 2026-10-08, D5):
p24-reviewer(least-privilege review-only App) posts the council review comments + verdict, but its approve does not count towardrequired_approving_review_countonmain— so App 2109526 (p24-infra-admin) posts the count-satisfying approve. A human (radieu) approve also counts. No session role self-approves its own worker-authored code. p24-reviewerposted its first real approval 2026-10-08 (PR #7604), alongside the App 2109526 approve that actually satisfied the branch-protection gate (see §6). Merged PRs #7614 and #7615 followed the same dual-approve pattern.sys-admin/sys-securitymay read SOPS key names for verification; they never write SOPS.
3. Flow per repo type (+ enforcement level)
Enforcement level = how the “approve-before-merge” rule is enforced:
hard— GitHub branch protection (required_approving_review_count: 1,require_last_push_approval: true,dismiss_stale_reviews: true). The platform blocks a non-conforming merge.process— no branch protection available (GitHub Free private repo); the rule is enforced by worker-prompt discipline + a detective post-merge audit, not by GitHub.
| Repo type | Branch base | PR target | Promotion chain | Merger | Enforcement |
|---|---|---|---|---|---|
| p24-infra | origin/main | main (direct — no dev step) | none | review-pr worker [D2] / radieu | hard |
| et-operational-platform | origin/dev | dev | dev → rc-staging (throwaway) → staging → rc → main | review-pr worker [D2] / radieu | process (until #7612 E1–E6 land) |
Pinbox24 GitLab (pinbox24/*) | development | development | GitLab CI on bms-1 (merge ⇒ deploy, see §8) | infra-task worker (sys-admin) | process (group Owner PAT) |
- p24-infra branching rule (single
main,feat/*|fix/*|patch/*|plan/*fromorigin/main) and the frozenorigin/devare owned bystandards/domains/branching.md(top note). et-op promotion gates (/staging,/staging-review-to-rc,/rc-to-main, lock ledger et-op#1918) are owned by et-op’s ownCLAUDE.md— do not restate them here. - et-op approval is required before merge too (decided 2026-10-08). Because et-op is a GitHub Free
private repo with no branch protection, enforcement is
process: workers must open-PR-and-stop, and only the review-pr worker merges after ap24-reviewer/human APPROVE on the current head sha. The enforcement redesign (replace worker self-merge, add a merge-gate, add a post-merge audit) is tracked as E1–E6 on #7612 — until those land, the rule is honour-system.
4. Commit rules
- Author identity per host: target
ai-dev-*@zintegrowana.onlinefor worker commits (D1 — see §1 observed-vs-target). Human interactive commits areradieu <radieu@gmail.com>. - Signing:
[D3]open — observedmainsquash commits are GitHub web-flow signed (verified); no local per-role signing today. Tracked, not yet decided. - Format, closing keywords, native-linker phrasing → owned by
standards/domains/branching.mdand CLAUDE.md §Branching. TheCo-Authored-By:attribution trailer is defined there (do not restate or hard-code a model name here). UsePartially implements: #Nfor a deliberate subset; keepclose/fix/resolvewords out of the ~3 words before any bare#N. - Never commit from the orchestrating checkout when a worktree is the convention (CLAUDE.md §Agent Workflow — Worktree Branch Isolation).
5. PR rules
Title/body format, labels (ai-review-queued, human-action, blocked-on-dependency), draft policy,
and the partial-scope keyword are owned by branching.md + CLAUDE.md §Branching and the worker prompt
(infra/agent-prompts/worker-issue.md Steps 8–9). Not restated here. The one identity fact: a PR is
opened by the worker bot (or radieu for a human PR); dev-reviewer never opens PRs.
6. Review & approval rules
- Reviewer identity (review verdict):
p24-reviewer(App 5208530) is the review identity — the review-pr worker mints its token (scripts/gh-app-token --app reviewer, key ingithub-reviewer-app.env.sops) and runsgh pr review --approveto post the council review comments and verdict. It holds onlypull_requests:write/contents:read/issues:write/metadata:read. - Its approve does NOT count toward the merge gate (decided 2026-10-08, D5). On the real PRs #7604,
#7606–#7608 the
gh pr review --approvereturned exit 0 butreviewDecisionstayedREVIEW_REQUIREDand the review’sauthorAssociationwasNONE— ap24-reviewerapprove alone leaves the PR BLOCKED. Probable cause: the App hascontents:readonly, so GitHub does not treat it as an eligible reviewer forrequired_approving_review_count(inferred from the logs, not proven). The decision is not to grantp24-reviewercontents:write. - Counting approve: App 2109526 (
p24-infra-admin) posts the count-satisfying approve — the dual-approve pattern (p24-reviewerverdict + App 2109526 approve). App 2109526 never pushes PR branches, so its approve meetsrequire_last_push_approval. A human (radieu) approve also counts ([D4]= allow). How-to is owned byreviewer-github-app.md; live state byreviewer-github-app-operations.md. - Fallback chain (when the App 2109526 token cannot be minted): last resort is a worker-identity
approve, which may self-collide and then needs a human merge click. Mechanics + the residual collision
case are owned by
ai-pr-auto-review.mdand CLAUDE.md §Branching. require_last_push_approval+dismiss_stale_reviews: an approval is bound to the head sha; any push after it dismisses prior reviews. The worker’ssynchronizere-queue (#6387) re-reviews after a post-approval push so it never deadlocks. Full semantics →ai-pr-auto-review.md.
7. Merge rules
- Who merges (
[D2]): the review-pr worker merges PRs — worker-authored and human-authored — only after a valid APPROVE. A human (radieu) may also merge (--adminreserved to human-owner). Workers in other roles do not self-merge (the et-op self-merge path is being removed under #7612 E1). - Method: squash + delete branch on p24-infra. (A
--mergevs--squashinconsistency between the worker prompts and the review-pr worker is tracked as #7612 E6.) - Failure path: if the App token cannot be minted and a same-account approve self-collides, the merge
stops and a human merge click is required — state it as a fact, do not loop
gh pr merge(CLAUDE.md §Branching).
8. Deploy rules
Deploy is a consequence of merge, not an identity. No role “deploys” — a merge fires a workflow that deploys under a service credential.
| Trigger | Workflow / mechanism | Runner | Credential (NAME) | Target |
|---|---|---|---|---|
Merge to main (config/secrets) | secrets-sync.yml, deploy-monitoring-config.yml | GH Actions → SSH | AGE_KEY_GHA, VPS_SSH_PRIVATE_KEY | vps-i1 / bms-4 |
Merge to main (CF Worker) | wrangler deploy in CI | GH Actions | CF deploy token (cloudflare.env.sops / CF_WORKERS_EDIT_TOKEN) | Cloudflare |
| Merge to Vercel-tracked branch | Vercel git integration or reusable Action | Vercel / GH Actions | VERCEL_TOKEN | Vercel |
| GitLab MR merge to a deploy-coupled branch | .gitlab-ci.yml deploy stage | GitLab runner (bms-1) | runner creds | Pinbox24 prod (~30 s) |
- Vercel commit-author seat requirement
[D7]: Vercel’s git integration gates auto-deploy on the merging commit’s GitHub identity holding a contributing Vercel seat — a bot author without one is silently blocked. The decided direction is author-independent deploy via aVERCEL_TOKENAction (.github/workflows/reusable-deploy-vercel.yml, #7592), which bypasses the seat check, rather than buying bot seats. Root cause + rollout owned byvercel-deploy-blocked-git-author-access.md; Vercel access forai-dev-bms4-2is tracked on #7590 (D7). - GitLab merge ⇒ deploy: merging a
pinbox24/*MR whose target branch couples deploy in.gitlab-ci.ymldeploys to production within ~30 s with no intercept window. Always check the target branch’s.gitlab-ci.ymlfor a coupled deploy stage before merging. Owned byw3-w4-stack-operations.md§2.
9. Per-host operating profile
For each host: default gh account, git config, allowed roles, how to switch. The authoritative
per-host detail lives in docs/environments/<host>.md — this section links, it does not copy.
| Host | Default gh / git identity | Roles | Notes |
|---|---|---|---|
| lap2 | radieu | human-owner, any interactive role | Active interactive host. lap2.md |
| windows-dev | radieu (both radieu + ai-dev-windev-1 logged in; switch with gh auth switch) | human-owner, interactive | Dormant until ~2026-10-15, then 2nd interactive host. Git identity stays radieu globally. windows-dev.md |
| dev-workstation | radieu | human-owner | dev-workstation.md |
bms-4 (claude-runner) | AI-Dev-BMS4-1 | dev-coder, dev-reviewer, dev-tester, sys-admin, secret-manager, infra-task | primary dispatch. ai-dev-bms4-1.md, bms-4.md |
bms-4 (claude-runner-2) | ai-dev-bms4-2 | same | 2nd worker account. |
vps-i1 (claude-runner) | AI-Dev-IO1 | monitoring-ops, fallback worker | ai-dev-io1.md |
Per-host env docs may still describe windows-dev as the active box / lap2 as new — aligning those status banners with the decided lap2-active / windows-dev-dormant state is a separate doc-sweep (do not rewrite them from this playbook).
10. Verification commands
# Who am I (this host)
gh auth status
git config user.name; git config user.email
# Who authored / committed / signed recent commits on main
git log origin/main --no-merges --format='%h|%an|%ae|%cn|%G?' -n 20
# Who opened vs merged recent PRs (identity split)
gh pr list --repo radieu/p24-infra --state merged --limit 15 \
--json number,author,mergedBy,title \
--jq '.[] | "#\(.number) author=\(.author.login) mergedBy=\(.mergedBy.login // "?")"'
# Who approved a given PR (expect p24-reviewer[bot] primary)
gh api repos/radieu/p24-infra/pulls/<N>/reviews \
--jq '.[] | "\(.user.login) [\(.user.type)] \(.state)"' | sort -u
# Worker gh identity on each SSH worker → worker-gh-auth-standard.md §Verify11. Exceptions & escalation
| Situation | What it means | Owning playbook |
|---|---|---|
p24-reviewer approve alone leaves PR BLOCKED | expected — the review-only App approve does not count toward required_approving_review_count; the worker posts the App 2109526 approve to satisfy the gate (dual-approve) | §6, ai-pr-auto-review.md |
Self-approval collision (require_last_push_approval fails after a worker-identity approve) | reviewer == pusher account; mint App-2109526 approve, else human merge | CLAUDE.md §Branching, ai-pr-auto-review.md |
| Vercel deploy silently blocked | merging commit author has no Vercel seat → use the token Action | vercel-deploy-blocked-git-author-access.md |
Stuck ai-review-queued (no reviewer comment) | wait a dispatcher cycle before escalating; don’t self-review | CLAUDE.md §Branching |
p24-reviewer token mint failure | fall back to App 2109526, then worker, then human | reviewer-github-app.md |
| GitLab MR would deploy on merge | coupled deploy stage — confirm before merging | w3-w4-stack-operations.md §2 |
| Auto Mode classifier blocks an identity-switching approve | surface to the user; don’t work around | CLAUDE.md §Branching (Auto Mode note) |
12. Open decisions
Resolved 2026-10-08 (user): D1 worker author = ai-dev-*@zintegrowana.online (shipped by #7613 /
PR #7614) · D2 review-pr worker merges PRs (incl. human-authored) only after approve · D4 a
human may approve · D5 p24-reviewer stays review-only and is not granted contents:write; its
approve does not count toward the merge gate, so App 2109526 (p24-infra-admin) remains the counting
approver (dual-approve pattern) in addition to CI / worker clone / gh secret set / n8n.
Still open (tracked, not blocking this doc):
| # | Decision | Status |
|---|---|---|
| D3 | Commit signing (off / per-role SSH signing / web-flow only) | TBD — web-flow signing observed on main |
| D6 | Register ai-dev-windev-1 on lap2 too, or windows-dev only | TBD |
| D7 | Vercel seats for bot authors vs token-Action deploy | token-Action direction chosen (#7592); seat for ai-dev-bms4-2 tracked #7590 |
13. References
standards/domains/branching.md— branch/commit/PR format, closing keywords, p24-infra single-mainexceptionworker-gh-auth-standard.md— workerghauth + per-worker OS-account registryreviewer-github-app.md+reviewer-github-app-operations.md—p24-reviewerApp (how / state)ai-pr-auto-review.md— review pipeline mechanics,require_last_push_approval, merge/escalationgithub-app-token-integration.md+gh-app-token-deploy.md— App-token minting across runtimesvercel-deploy-blocked-git-author-access.md— Vercel commit-author seat gate + token-Action fixw3-w4-stack-operations.md— Pinbox24 GitLab MR merge + coupled deploydocs/environments/<host>.md— per-host operating profile- CLAUDE.md §Role Enforcement, §Branching — session roles + the approve/merge collision rules
- Related issues: #7478 (
p24-reviewerApp), #7574 (review-pr worker switch), #7612 (et-op approve-before-merge enforcement E1–E6), #7590 (Vercel access forai-dev-bms4-2, D7), #7613 (worker commit author fix, PR #7614), #7481 (role-PAT → GitHub App; out of scope here)
First written for #7611. Keep the matrix here canonical — update this file on any identity change, and link to it from docs that previously carried a fragment of it rather than copying the matrix back.