pr-merge.sh:417 blocks the squash-trailer remedy on exactly the PRs carrying the owner's own commits (unlinked commit address on account id=2) #1108

Open
opened 2026-08-07 16:58:17 +00:00 by Mos · 1 comment
Contributor

Summary

pr-merge.sh:417 refuses to merge a PR when any commit has author.login == NULL. On
git.mosaicstack.dev that condition currently fires on four open PRs — #965, #1022, #1023, #1024
and every one of the six NULL-resolving commits is authored Jason Woltje.

The cause is not a missing account. Account jason.woltje (id=2) exists; it is registered with a
noreply-form address on the mosaicstack.dev domain, while his commits here are authored with a single
external-domain address on uscllc.com. Gitea cannot resolve the commit address to the account, so
author.login comes back NULL. (One distinct address across all four PRs. No address value is recorded
in this issue
— shape and a truncated digest only: sha256[:10]=ccb5a21b.)

Why it matters

pr-merge.sh on main carries full --co-author-trailers machinery (:73-74 flag, :442 emits
Co-authored-by:). A squash that emits trailers preserves every constituent author and satisfies
Constitution gate 15 (squash-only). That is the only attribution remedy that does not require splitting a
PR by author and re-running review + CI.

:417 blocks that remedy for exactly the commits it would most protect. Measured contrast: on
git.uscllc.com all four held PRs (#3130, #3121, #3123, #3127) have zero NULLs — every author is a
fleet seat with a registered address — so route D is viable there and blocked here.

Asks (in cost order)

  1. Link the commit address to account jason.woltje (id=2) on git.mosaicstack.dev. One account
    setting. Account-settings work on the owner's own account — no agent seat can or should do it.
    Bound, unverified: Gitea resolves on a verified linked email. Nobody has verified that this
    address can be verified on this instance, so linking is the diagnosed cause of the NULL, not a proven
    fix. Confirm by re-reading author.login on #965 afterwards.
  2. Design decision — :442/:417: should a squash record the commit's AUTHOR, or only a LINKED
    ACCOUNT?
    A Co-authored-by: trailer is a plain string and has never required a registered address.
    As written, an unlinked address makes the wrapper drop the author entirely rather than drop the
    clickable link. :359-361 says so in its own words: "This gate checks ATTRIBUTION LINKAGE, not
    AUTHORSHIP."

Also relevant

  • The trailer machinery lives only in main (23,435 B). The deployed wrapper is 7,901 B with zero
    trailer code and zero production callers pass the flag ⇒ delivery is gated on #1072.
  • Related: #1072 (framework delivery path), #1080 (reviews bind to commit_id).

Measured by tl-mosaic (read-only homelab seat, 403 on read:issue); filed by mos-claude at its request.

## Summary `pr-merge.sh:417` refuses to merge a PR when **any** commit has `author.login == NULL`. On `git.mosaicstack.dev` that condition currently fires on four open PRs — **#965, #1022, #1023, #1024** — and **every one of the six NULL-resolving commits is authored `Jason Woltje`**. The cause is **not** a missing account. Account `jason.woltje` (id=2) exists; it is registered with a `noreply`-form address on the `mosaicstack.dev` domain, while his commits here are authored with a single external-domain address on `uscllc.com`. Gitea cannot resolve the commit address to the account, so `author.login` comes back NULL. (One distinct address across all four PRs. **No address value is recorded in this issue** — shape and a truncated digest only: `sha256[:10]=ccb5a21b`.) ## Why it matters `pr-merge.sh` on `main` carries full `--co-author-trailers` machinery (`:73-74` flag, `:442` emits `Co-authored-by:`). A squash that emits trailers preserves every constituent author **and** satisfies Constitution gate 15 (squash-only). That is the only attribution remedy that does not require splitting a PR by author and re-running review + CI. `:417` blocks that remedy for exactly the commits it would most protect. Measured contrast: on `git.uscllc.com` all four held PRs (#3130, #3121, #3123, #3127) have **zero** NULLs — every author is a fleet seat with a registered address — so route D is viable there and blocked here. ## Asks (in cost order) 1. **Link the commit address to account `jason.woltje` (id=2) on `git.mosaicstack.dev`.** One account setting. Account-settings work on the owner's own account — no agent seat can or should do it. ⚠ **Bound, unverified:** Gitea resolves on a *verified* linked email. Nobody has verified that this address can be verified on this instance, so linking is the diagnosed cause of the NULL, not a proven fix. Confirm by re-reading `author.login` on #965 afterwards. 2. **Design decision — `:442`/`:417`: should a squash record the commit's AUTHOR, or only a LINKED ACCOUNT?** A `Co-authored-by:` trailer is a plain string and has never required a registered address. As written, an unlinked address makes the wrapper drop the author entirely rather than drop the clickable link. `:359-361` says so in its own words: *"This gate checks ATTRIBUTION LINKAGE, not AUTHORSHIP."* ## Also relevant - The trailer machinery lives **only in `main`** (23,435 B). The deployed wrapper is 7,901 B with zero trailer code and zero production callers pass the flag ⇒ delivery is gated on #1072. - Related: #1072 (framework delivery path), #1080 (reviews bind to `commit_id`). Measured by `tl-mosaic` (read-only homelab seat, 403 on `read:issue`); filed by `mos-claude` at its request.
Author
Contributor

Ask 2 has a concrete answer in the code — the trailer is already half-raw

Measured by tl-mosaic against origin/main:pr-merge.sh, recorded here so it survives the fleet session:

line what it does
:412 commit_author = commit.get("author") — the raw git author: name AND email
:413 email = commit_author.get("email") — raw email, and it is used
:415 login = provider_author.get("login") — the resolved account
:417-425 if not login:block, exit 75. :418 puts email in the diagnostic, so the function demonstrably has the address in hand at the moment it refuses
:442 trailers.append(f"Co-authored-by: {login} <{email}>")

So the emitted trailer is already a mix of resolved login + raw email. And
commit_author.get("name") — the actual author name — is fetched at :412 and never read anywhere in
the function
.

⇒ Preserving the author is therefore not a new capability; it is stopping the function from discarding a
field it already fetched
. The shape of the change:

  • :442f"Co-authored-by: {commit_author.get('name')} <{email}>"
  • :439 → dedup currently keys on login; would key on email or name
  • :417degrade to the raw name instead of blocking
  • :429 → the [A-Za-z0-9_.-]+ character guard is the only part that genuinely depends on a login; a name
    field needs a different validator, not that one.

This resolves :359-361's own note — "This gate checks ATTRIBUTION LINKAGE, not AUTHORSHIP" — in the
direction its author warned about: as written, an unlinked address loses the author entirely rather
than losing the link.

Scope, and the cost, stated plainly

Linking the address (ask 1) fixes six commits. Fixing :442/:417 fixes the whole class, including
authors that have no provider account and never will
Hermes Agent, mosaic-coder, ms-lead-reviewer.

The real cost, not hidden: raw-name trailers are unverified self-asserted strings — which is exactly
what :359 says git author metadata is. Preserving them records claimed authorship. That is a deliberate
trade and it is the repo owner's to make.

No patch is proposed here. This is framework code with its own review path, and --co-author-trailers
has never been exercised in production by anything.

Cross-estate contrast (measured by orchestrator, git.uscllc.com)

:417 NULLs on the four held USC PRs: #3130 8 commits → 0 · #3121 3 → 0 · #3123 4 → 0 ·
#3127 4 → 0. Every author there is a fleet seat with a registered address. So the remedy works where
the injured party is an agent and fails where it is the human — not a design choice anybody made, just
whose email happened to be linked.

## Ask 2 has a concrete answer in the code — the trailer is *already* half-raw Measured by `tl-mosaic` against `origin/main:pr-merge.sh`, recorded here so it survives the fleet session: | line | what it does | |---|---| | `:412` | `commit_author = commit.get("author")` — the **raw git author: name AND email** | | `:413` | `email = commit_author.get("email")` — raw email, **and it is used** | | `:415` | `login = provider_author.get("login")` — the resolved account | | `:417-425` | `if not login:` ⇒ **block, exit 75**. `:418` puts `email` in the diagnostic, so the function demonstrably **has the address in hand at the moment it refuses** | | `:442` | `trailers.append(f"Co-authored-by: {login} <{email}>")` | So the emitted trailer is already a mix of **resolved login + raw email**. And `commit_author.get("name")` — the actual author name — is fetched at `:412` and **never read anywhere in the function**. ⇒ Preserving the author is therefore not a new capability; it is *stopping the function from discarding a field it already fetched*. The shape of the change: - `:442` → `f"Co-authored-by: {commit_author.get('name')} <{email}>"` - `:439` → dedup currently keys on `login`; would key on email or name - `:417` → **degrade to the raw name instead of blocking** - `:429` → the `[A-Za-z0-9_.-]+` character guard is the only part that genuinely depends on a login; a name field needs a different validator, not that one. This resolves `:359-361`'s own note — *"This gate checks ATTRIBUTION LINKAGE, not AUTHORSHIP"* — in the direction its author warned about: as written, an unlinked address loses **the author entirely** rather than losing **the link**. ### Scope, and the cost, stated plainly Linking the address (ask 1) fixes six commits. Fixing `:442`/`:417` fixes the whole class, **including authors that have no provider account and never will** — `Hermes Agent`, `mosaic-coder`, `ms-lead-reviewer`. ⚠ **The real cost, not hidden:** raw-name trailers are unverified self-asserted strings — which is exactly what `:359` says git author metadata is. Preserving them records *claimed* authorship. That is a deliberate trade and it is the repo owner's to make. ⛔ No patch is proposed here. This is framework code with its own review path, and `--co-author-trailers` has never been exercised in production by anything. ### Cross-estate contrast (measured by `orchestrator`, `git.uscllc.com`) `:417` NULLs on the four held USC PRs: **#3130** 8 commits → 0 · **#3121** 3 → 0 · **#3123** 4 → 0 · **#3127** 4 → 0. Every author there is a fleet seat with a registered address. So the remedy works where the injured party is an agent and fails where it is the human — not a design choice anybody made, just whose email happened to be linked.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1108