From 66bf8fad6b90f2b31e715e9a3b47593e1c351be6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Sep 2026 15:56:56 +0000 Subject: [PATCH] chore(loop): attribute loop commits to github-actions[bot] agentEnv() injected 'tiny-oss loop ' as the git identity under auto. That address belongs to the real, unrelated GitHub user @loop (id 1519971), so every loop commit - 8ec1b1e (PR #50) and 4d2735a/35c7312 (PR #55) - was falsely attributed to a stranger (#52, #56). Use GitHub Actions' own bot instead, the same identity the host's PR is authored by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>. A bot noreply address is not a user account, so it cannot be squatted. Only future commits change; the historical ones stay as they are. --- scripts/loop/README.md | 2 +- scripts/loop/shared/agent.mjs | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/loop/README.md b/scripts/loop/README.md index 9791aca..1d99ed7 100644 --- a/scripts/loop/README.md +++ b/scripts/loop/README.md @@ -264,7 +264,7 @@ reason a future reader may see the parameter and wonder where it came from. | `validatePush` | `entry.mjs` | `pr-opened` without a valid proposal (wrong branch, empty title, another task's number, or `writeLevel=report`) is downgraded to `failed`, so a task can never sit in `waiting-merge` waiting for a PR nobody opened. | | `ensureLoopPrBody` | `planActions` | Repairs the PR body's `Closes #` / `loop-task: #` markers. The router requires both, and a missing marker would make the loop's own PR look external — no acceptance row, and its merge would close the task by the wrong path. | | PR number recorded | `finishRun` | The number comes back from `gh pr create` and lands in `task.prs` + a `pr-created` timeline row. | -| git identity | `agentEnv` | `GIT_AUTHOR_*`/`GIT_COMMITTER_*` are injected under `auto`; a fresh runner has no global git config, and the commit itself is local (no credential involved). | +| git identity | `agentEnv` | `GIT_AUTHOR_*`/`GIT_COMMITTER_*` are injected under `auto` as GitHub Actions' own bot, `github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>` — the same identity the host's PR comes from. A fresh runner has no global git config, and the commit itself is local (no credential involved). The earlier `loop@users.noreply.github.com` belonged to the real, unrelated user `@loop`, so every loop commit was falsely attributed to them (#52, #56). | Note what is **not** load-bearing: the host-versus-agent split. It exists because the writes must be derived from the agent's result file in one place that can enforce the diff --git a/scripts/loop/shared/agent.mjs b/scripts/loop/shared/agent.mjs index 84845fa..3c5a4df 100644 --- a/scripts/loop/shared/agent.mjs +++ b/scripts/loop/shared/agent.mjs @@ -191,9 +191,17 @@ export function agentEnv(writeLevel, base = process.env) { // Product stages commit the branch the host pushes, and the identity must not come // from the sandbox's global git config (there is none on a fresh runner). Set it // here rather than making the agent discover it: a commit is a local operation. + // + // The identity is GitHub Actions' own bot (`github-actions[bot]`), matching the PR + // author the host opens with the job token. The previous + // `loop@users.noreply.github.com` resolved to the real, unrelated account @loop + // (id 1519971), so every loop commit was falsely attributed to a stranger (#52, + // #56). A bot noreply address is not a user account, so it cannot be squatted the + // way a bare login can. if (writeLevel === 'auto') { - env.GIT_AUTHOR_NAME = env.GIT_AUTHOR_NAME ?? 'tiny-oss loop'; - env.GIT_AUTHOR_EMAIL = env.GIT_AUTHOR_EMAIL ?? 'loop@users.noreply.github.com'; + env.GIT_AUTHOR_NAME = env.GIT_AUTHOR_NAME ?? 'github-actions[bot]'; + env.GIT_AUTHOR_EMAIL = env.GIT_AUTHOR_EMAIL + ?? '41898282+github-actions[bot]@users.noreply.github.com'; env.GIT_COMMITTER_NAME = env.GIT_COMMITTER_NAME ?? env.GIT_AUTHOR_NAME; env.GIT_COMMITTER_EMAIL = env.GIT_COMMITTER_EMAIL ?? env.GIT_AUTHOR_EMAIL; }