Files
stack/docs/scratchpads/pr-merge-message-field.md
T
2026-08-05 18:57:28 -05:00

12 KiB
Raw Blame History

PR merge squash message field

  • Charter: /home/hermes/agent-work/CHARTER-PRMERGE-MESSAGE-FIELD.md
  • Owner: be-coder-08
  • Branch: fix/pr-merge-message-field
  • Base: remote main / local origin/main at 85d2108e4ed15c744ad3b87a5b629e7b2d39405a
  • Estate: HOMELAB tooling shared by HOMELAB and USC

Objective

Add an optional, identity-checked Gitea squash message to pr-merge.sh so genuine multi-author PRs retain non-poster branch authors without weakening hardcoded squash behavior.

Binding requirements

  1. Do remains hardcoded to squash; no provider/repository default may select merge style.
  2. A verified trailer uses a PR commit's linked author.login and that same commit's author email. No /users/{login} primary-email lookup occurs. Recorded rationale: this asks only what the provider can answer.
  3. A commit with author.login null blocks before merge, prints both the null provider fact and commit email fact, and names the escalation principal.
  4. The BLOCK arm must be observed firing; a normal canonical single-author API payload remains explicit squash plus its reviewed head_commit_id.
  5. Every provider mutation is read back from the provider; no real PR is merged during tests.

Derived interface decisions

  • Add --co-author-trailers rather than accepting arbitrary message text. The wrapper enumerates PR commits and constructs trailers, making an unchecked Co-authored-by line unexpressible.
  • Require --escalate-to PRINCIPAL with --co-author-trailers, so the BLOCK diagnostic always names a principal rather than a generic role.
  • Do not expose MergeTitleField separately. When trailers exist, set it from the provider PR title and set MergeMessageField only to construction-generated trailers. This preserves one provider source for the title and avoids an unrelated caller-controlled degree of freedom.
  • Preserve first-commit order and emit one trailer per distinct non-poster author.login, using that first linked commit's own email.

Canonical delivery plan

  1. Port the capability into the installed source of truth, packages/mosaic/framework/tools/git/pr-merge.sh; do not retain infra/fleet/tools/git as a second copy.
  2. Preserve canonical --expect-head, exact head branch/repository/SHA queue inspection, Gitea atomic head pinning, GitHub --match-head-commit, and delete-after-merge semantics.
  3. Do not port the deployed-only --skip-queue-guard bypass. Add the focused harness to the canonical framework-shell suite and re-establish RED/GREEN on the packaged baseline.
  4. Deliver through a reviewed package release followed by mosaic update with its default framework reseed. The installer snapshots, manifest-syncs framework-owned tools/**, and rolls back on failure.
  5. Before either estate relies on the change, require installed/package hash equality, MergeMessageField presence, and a green focused harness. Release/reseed ownership is currently unassigned and blocks activation after source merge.

Evidence

  • RED against the byte-identical deployed baseline (sha256 08a65e8584c5…): rc 1 with eight named failures. The wrapper rejected --co-author-trailers; the null-login path emitted none of the required BLOCK facts/principal; and both verified/ordinary API paths failed the stdin-config credential assertion (ordinary path exposed the fixture token through curl argv). Log: /home/hermes/agent-work/be-coder-08/evidence/prmerge-message-field-red.log.
  • GREEN on the deployed-baseline candidate: verified linked multi-author payload, null-login BLOCK, required named principal, explicit squash, stdin-config token transport, and absence of /users lookup all passed. Log: /home/hermes/agent-work/be-coder-08/evidence/prmerge-message-field-green.log.
  • RED against canonical packaged baseline c581ef48…: rc 1 with 32 assertions. It rejects the new option, and the first harness version did not satisfy canonical head branch/repository/SHA metadata. Log: /home/hermes/agent-work/be-coder-08/evidence/prmerge-packaged-baseline-red.log. The port adapts the fixture rather than weakening canonical head controls.
  • Provider capability probe against git.mosaicstack.dev: authenticated be-coder-08 POST to deliberately nonexistent PR 2147483647 with both message fields returned JSON HTTP 404; the unauthenticated same request returned JSON HTTP 401 (not the charter's predicted 403). The authenticated-vs-unauthenticated differential proves write authorization resolved while no mergeable subject existed. tl-mosaic ruled the literal non-load-bearing: preserve the observed 404/401 pair and do not manufacture a 403 case. No cause was inferred and no real PR was targeted.
  • Provider-generated trailer behavior is not treated as exclusive or absent. The wrapper's VERIFIED/BLOCK decision binds each requested non-poster trailer to commit author.login plus that commit's email; it does not assume MergeMessageField is the squash's only trailer source. The poster is omitted from the constructed list because the resulting squash author already records the poster; any additional provider-generated trailer is outside this change's unmeasured mechanism.
  • An early candidate SHA-256 5de32876990e4f26920448cb3220cc7f1146d558b4dd2bc1ee1a2abee2f2cbe6 passed the initial harness, then author-side review found credential-fallback and argv-exposure defects. The live deployed wrapper was atomically restored to baseline SHA-256 08a65e8584c52c6d41ea1c686f8b95585c21e4b37320a2447eba09359a0e02c1; the remediated candidate remains only in the worktree.

Remediation and current review state

  1. Token and Basic Auth now use stdin curl configuration, not argv. PR title, contributor email, and the JSON payload also remain out of child argv.
  2. Each credential attempt binds commit inspection and merge. A token failure during either inspection or mutation causes Basic fallback to repeat inspection before mutation; the payload pins the inspected head_commit_id.
  3. Focused tests cover token-resolution fail-closed behavior, both HTTP-401 fallback seams, metadata/credential argv absence, null-login BLOCK, explicit squash, canonical reviewed-head binding, unchanged ordinary payload, and retained log-safe provider diagnostics. Token-resolution RED: /home/hermes/agent-work/be-coder-08/evidence/prmerge-token-resolution-red.log.
  4. Codex review rounds 35 requested retained provider error text, log-safe provider diagnostics, fail-closed credential fallback, stable value-option parsing, and PR-title trailer-injection prevention. These are remediated with regression assertions. A post-remediation independent review is still required.
  5. Accepted linkage limitation: author.login resolution proves that the commit address maps to a registered provider account. It does not prove that the named principal authored the commit because Git author metadata is self-asserted. This gate checks attribution linkage, not authorship; commit signing is out of scope and currently unadopted. Coordinators explicitly ruled that this does not add a third state.
  6. Codex's sandbox could not execute the harness because its checkout was read-only; that environmental limitation is recorded separately from host-side test results.

Disposable provider fixture acceptance

  • Use a retained scratch repository only, with two branch authors and author != committer on at least one commit.
  • Arm A supplies a message-field trailer for one non-poster; record whether that value lands without forcing the partial-pair result into under-specified APPENDS/REPLACES labels. Demonstrate an absence control.
  • Arm B includes a registered trailer for a different non-poster on a branch commit; record whether it survives or drops. Verify identity through an existing commit whose author.login resolves and demonstrate an absence control.
  • Parse landed trailers key-agnostically with ^[A-Za-z-]+-[Bb]y: and record generated poster pair presence/absence plus resulting poster attribution.
  • Record /users/<login> status and raw email only as non-gating estate telemetry. Never read active, visibility, or any profile field as an identity gate.
  • Use distinct principals: poster be-coder-08, merger Mos, Arm A be-coder-07, and Arm B be-coder-06. Capture every trailer-shaped line verbatim and in order. Zero trailer lines means the generator did not fire and the run is VOID, not evidence that either arm dropped.
  • Report the same read-back evidence to mos-claude on socket default and tl-mosaic on socket mosaic-fleet. Report values rather than mechanism inferences and stop on any poster-attribution regression.

Fixture preflight

  • Retained public repository: mosaicstack/prmerge-trailer-fixture; PR #1, posted by be-coder-08 and reserved for merge by Mos.
  • Existing mosaicstack/stack commits resolve be-coder-07 and be-coder-06 through author.login; exact addresses are [email protected] and [email protected].
  • Non-gating HOMELAB telemetry for authenticated reader be-coder-08: /api/v1/users/be-coder-06 returned HTTP 200 with raw email value [email protected].
  • Provider preflight showed PR commit enumeration is newest-first. A new RED test proved that deriving head_commit_id from the final array element selected the wrong commit. The candidate now reads .head.sha from the authenticated PR endpoint before enumeration, verifies it appears in the commit set, and atomically pins that SHA in the explicit squash payload. RED: /home/hermes/agent-work/be-coder-08/evidence/prmerge-head-order-red.log.
  • Fixture PR head f6ba6e5105031fa21f5ff7bd8e4379d99c16e1de has author.login=be-coder-07, committer.login=be-coder-08, and branch-message trailer Co-authored-by: be-coder-06 <[email protected]>.

Fixture result

  • Mos merged retained fixture PR #1 through staged candidate SHA-256 60e779a85fd13b729d859ea7c986d1e9b1641b97991611329226c1b3113ffb6e; resulting squash commit: 3f550715d9bc716426fd355a65fe997b3a90fa7d with one parent.
  • Provider read-back: poster/commit author be-coder-08, committer/merger Mos. The run is non-void.
  • Trailer-shaped lines, verbatim and in order:
    1. Co-authored-by: be-coder-07 <[email protected]>
    2. Co-authored-by: be-coder-08 <[email protected]>
  • Arm A supplied field value (be-coder-07) landed. Arm B branch trailer (be-coder-06) dropped. Both fabricated absence controls remained absent. No Co-committed-by: line landed.
  • The candidate payload construction explicitly excludes the poster and supplied only the Arm A be-coder-07 line. Therefore the landed poster line was provider-generated, not candidate-composed. The raw result supports FIELD LANDS, BRANCH DROPS, and POSTER GENERATED; it does not support a claim that candidate code supplied the poster. Evidence: /home/hermes/agent-work/be-coder-08/evidence/prmerge-fixture-readback.log and the retained provider object.
  • Retained fixture PR #2 measured the N=2 shape needed by #1030: supplied be-coder-07 then be-coder-06; both landed in that order, followed by the provider-generated poster line. No truncation or dedup occurred at N=2. Resulting squash: 39db9d13aed0….

Current hold point

PR mosaicstack/stack#1066 is open. Its first frozen head f4b162fa… was terminal-green in Woodpecker mosaic pipeline #2225, but that evidence becomes stale when the canonical port moves the head. The deployed wrapper remains baseline 08a65e85…; no manual copy will occur. Canonical port tests, commit amendment, rebase, one guarded force-with-lease, exact-head CI, and new independent review remain. Even after source merge, activation remains blocked on an assigned package-release/reseed owner and installed-byte read-back.