Skip to content

docs(contributing): squash-merge, and why --merge reds main - #176

Merged
localai-bot merged 2 commits into
mainfrom
row/ENG-LANDING-DISCIPLINE
Aug 8, 2026
Merged

docs(contributing): squash-merge, and why --merge reds main#176
localai-bot merged 2 commits into
mainfrom
row/ENG-LANDING-DISCIPLINE

Conversation

@localai-bot

Copy link
Copy Markdown
Collaborator

Why

main has been red on agent-record and documentation-checkpoint for three consecutive landings, and every one of them is the merge method rather than the content:

commit PR failure
da0a9d8d #157 POL-COMMIT-TRAILERS (squash message lost its trailers) + POL-DOC-*
c3db7804 / b97fc1d4 #172 POL-PR-REQUIRED on the content commit + POL-COMMIT-TRAILERS on the merge commit — mine, landed with --merge
3e5072d4 #174 POL-PR-REQUIRED on the content commit — same cause

gh pr merge --merge breaks two gates that read the commits a push actually lands on main:

  • check-role-discipline.py inspects every commit in the pushed range and wants each to name its row/<ROW-ID> branch or its PR as (#N). Squash-merge writes (#N) into the subject for free; --merge leaves the content commit with its branch subject, which names neither, so POL-PR-REQUIRED reports "reached main without a reviewed row/ PR"* about a commit that came from exactly such a PR.
  • check-commit-trailers.py reads the same range, and GitHub's generated Merge pull request #N from ... message carries no FOLLOWING_AGENTS_PROTOCOL paragraph and no trailers.

The part worth writing down is that neither is repairable after the push. Both gates are scoped over github.event.before..github.sha, and each run's before is the previous run's sha, so no later run re-covers a range that already went red. It is also invisible at PR time, because a PR is checked against its own base.

What this does and does not fix

Merging this squashed makes the next main run green, because every tree-scoped gate on main is already passing — verified at 80b08801: check-agent-record (ENGINE=144), check-gate-commands --check, audit-live-rows --check (203 live rows, 0 abandoned ACTIVE), check-role-discipline, check-policy, check-protocol-consistency, check-now-current, check-state-order, check-public-doc-tables, and the test_policy_contract / test_policy_waivers / test_check_commit_trailers suite (50 tests). Main's redness is entirely the diff-scoped range gates above.

This is documentation, not a guard. The permanent fix is a repository setting — allow squash only, disable merge commits — which needs admin rights I do not have. Recommend flipping it; this note then just explains the reason.

Two notes for anyone reading those failed logs:

  • The INTEGRATION FAILED: lines in agent-record are expected stdout from test_agent_gates.py's negative cases (16/16 pass). Likewise ROW-THAT-IS-NOT-THERE is fixture output from test_check_gate_commands.py. Neither is a failure, and both make the log read worse than it is.
  • fix(agents): demote abandoned ACTIVE rows so agent-record can pass #173 tried to fix this by demoting 42 ACTIVE rows to SPIKE. That premise did not reproduce — audit-live-rows --check reports 0 abandoned ACTIVE at that PR's own branch point — and the demotions covered Qwen3, DeepSeek-V2/V4, Laguna and Kimi-Linear, which have token-exact gates. Closed with the evidence.

Placement

In CONTRIBUTING.md rather than .agents/workflow.md: that file sits 7 bytes under its 12288-byte procedure budget and every paragraph of its non-generated prose is load-bearing, so buying room by trimming it would cost more than this note is worth. CONTRIBUTING.md is also where a contributor with merge rights actually looks.

Gates

check-policy, check-protocol-consistency, check-agent-record, check-readme-structure, check-public-doc-tables, check-role-discipline, plus check-commit-trailers and check-doc-checkpoint over the commit range — all OK on a worktree pinned at 80b08801. No record row, no capability claim, no code touched.

Please squash-merge this one.

mudler added 2 commits August 8, 2026 23:24
Landing a PR with `gh pr merge --merge` breaks two gates, and it has now
happened three times in a row on main: c3db780 (#172, mine), 3e5072d
(#174), and the trailer half on da0a9d8 (#157).

check-role-discipline.py inspects every commit in the pushed range and
wants each to name its row/<ROW-ID> branch or its PR as (#N). GitHub's
squash-merge writes (#N) into the subject for free. A --merge landing
leaves the content commit with the subject it had on the branch, which
names neither, so POL-PR-REQUIRED reports "reached main without a
reviewed row/* PR" about a commit that came from exactly such a PR.

check-commit-trailers.py reads the same range, and GitHub's generated
"Merge pull request #N from ..." message carries no
FOLLOWING_AGENTS_PROTOCOL paragraph and no trailers, so
POL-COMMIT-TRAILERS fails on the merge commit itself.

Both gates are scoped over github.event.before..github.sha and each run's
before is the previous run's sha, so no later run re-covers a range that
already went red. That is the part worth writing down: the failure is not
repairable after the push except by rewriting published history or
waiving it, and it is invisible at PR time because the PR is checked
against its own base.

Documented in CONTRIBUTING.md rather than .agents/workflow.md because
that file is 7 bytes under its 12288-byte procedure budget, and every
paragraph of its non-generated prose is load-bearing; buying room by
trimming it would cost more than this note is worth. CONTRIBUTING.md is
also where a contributor with merge rights actually looks.

This is documentation, not a guard. The permanent fix is a repository
setting - allow squash only, disable merge commits - which needs admin
and is left to the owner.

No record row, no capability claim, no code. Every tree-scoped gate on
main was already green before this change; main's red runs come entirely
from the diff-scoped range gates described above.

Gates: check-policy, check-protocol-consistency, check-agent-record,
check-readme-structure, check-public-doc-tables, check-role-discipline,
check-doc-checkpoint and check-commit-trailers over the range - all OK on
a worktree pinned at 80b0880.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude-Code:claude-opus-5 [Claude Code]
test_agent_role.py::test_landed_detached_commit_remains_strict_without_
pending_evidence failed on PR #176 and would fail on many PRs that have
nothing to do with what it asserts.

The test's subject is main()'s DECISION: a violation on a commit that has
landed, with no --pending-pr-head evidence, is strict (return 1) rather
than a REPORT (return 0). But it obtained that violation by relying on the
REAL HEAD to be one, and that coupling is live under CI.

On a pull_request event GitHub checks out the SYNTHETIC merge commit for
refs/pull/N/merge. inspect() sees two parents, so arrives_via_row_pr()
switches to the merged_messages branch and scans the PR's own commit
bodies with PR_REFERENCE = \(#\d+\)|#\d+, which matches a bare #123
anywhere. Any PR whose commit message cites an issue or PR number
therefore stops being a violation, main() returns 0, and the assertion
fails with 0 != 1. #176's message quotes (#157) and (#174) while
explaining these very gates, which is how it tripped.

Fixed by feeding main() a fixed violation through inspect/enforced rather
than depending on HEAD's message, plus a regression case pinning that a
message mentioning (#157) and #174 cannot flip the decision again.

Proven on a reconstructed synthetic merge, the exact shape CI checks out
(git merge --no-ff of the PR head into the base, detached):

  RED  old test on that checkout: AssertionError: 0 != 1, 41 tests,
       FAILED (failures=1) -- the same failure CI reported
  GREEN new test on the SAME checkout: 42 tests, OK

Not changed: PR_REFERENCE matching a bare #123 anywhere in a body also
means a direct push whose message merely mentions an issue satisfies
POL-PR-REQUIRED. That is a real hole, but tightening a policy gate's
strictness is a separate reviewed decision, not a CI repair.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: Claude-Code:claude-opus-5 [Claude Code]
@localai-bot

Copy link
Copy Markdown
Collaborator Author

Pushed a second commit: fix(ci): unbreak test_agent_role under a pull_request checkout.

The agent-record failure on this PR was not incidental — it is a real CI bug that would hit many PRs. test_landed_detached_commit_remains_strict_without_pending_evidence asserts a decision in main() (landed violation + no pending evidence ⇒ strict), but it obtained the violation by relying on the real HEAD to be one.

Under a pull_request event GitHub checks out the synthetic refs/pull/N/merge commit. inspect() sees two parents, so arrives_via_row_pr() scans the PR's own commit bodies with PR_REFERENCE = \(#\d+\)|#\d+, which matches a bare #123 anywhere. So any PR whose commit message cites an issue or PR number stops being a violation, main() returns 0, and the test fails 0 != 1. This PR's message quotes (#157) and (#174) while explaining these very gates, which is how it tripped.

Proven on a reconstructed synthetic merge — the exact shape CI checks out:

leg result
old test on that checkout AssertionError: 0 != 1, 41 tests, FAILED — the same failure CI reported
new test on the same checkout 42 tests, OK

Left alone deliberately: PR_REFERENCE matching a bare #123 anywhere also means a direct push whose message merely mentions an issue satisfies POL-PR-REQUIRED. That is a real hole in the gate, but tightening a policy gate's strictness is a separate reviewed decision, not a CI repair.

@mudler
mudler force-pushed the row/ENG-LANDING-DISCIPLINE branch from e39979a to 0d5a938 Compare August 8, 2026 23:24
@localai-bot
localai-bot merged commit d19a7ef into main Aug 8, 2026
11 checks passed
@mudler
mudler deleted the row/ENG-LANDING-DISCIPLINE branch August 8, 2026 23:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants