Summary
The agent-runtime ownership boundary gate keys each baselined violation on its line number, so an edit that merely shifts lines in a file containing a violation reddens the gate — reporting the same code as both a new "unbaselined violation" and a "stale baseline entry". Main is red on this right now, one day after #6462 re-baselined it, with zero actual change to the set of violations.
Proof: the violation set is identical, only lines moved
Regenerating the baseline from current main (2c579afc6) and comparing against the committed one:
baseline entries: 213 current findings: 213
differ when line INCLUDED : 5 pairs
differ when line EXCLUDED : 0
Zero difference once the line number is excluded. Same rules, same paths, same source text, same occurrence counts. Examples of entries whose only change is the line:
lifecycle.rs: 210 -> 70 let inherited_origin = crate::agent::turn_origin::capture();
runtime_session.rs: 1420 -> 1383 request_id: crate::agent::turn_origin::current_request_id(),
agent_chat.rs: 212 -> 197 if let Some(tx) = crate::agent::progress_sink::current_progress_sink() {
system_turn.rs: 88 -> 87 let result = with_origin(origin, agent.run_single(prompt))
factory.rs: 1198 -> 1206 let root = crate::agent::turn_workspace::current()?;
That is why the failure output lists the same lines on both sides — every "unbaselined violation" is also a "stale baseline entry".
Mechanism
scripts/ci/check-agent-runtime-boundary.mjs:341:
// Physical source locations are part of the temporary debt contract: a
// moved violation is stale debt, not a silently accepted occurrence.
const base = `${rule}\0${path}\0${line}\0${text}`;
Membership is then exact-JSON set comparison (:365-367), so a one-line shift is indistinguishable from "old violation deleted + new violation added".
The comment shows this is deliberate, and the intent is sound — a violation that moved should not be waved through unexamined. The cost may not have been weighed: the trigger is not "the violation changed", it is "any line above it changed". A PR that adds an import to agent_chat.rs inherits a red gate for seven violations it never touched.
Why this is worth fixing rather than re-baselining again
Re-baselining is not durable, and the history shows the treadmill:
| commit |
date |
|
180bec2f0 |
2026-09-22 |
ci: refresh agent runtime boundary baseline |
656c80e58 |
2026-09-23 07:09Z |
ci: re-baseline the agent-runtime ownership boundary (#6462) |
| — |
2026-09-23 13:00Z |
stale again |
Under six hours. Each refresh is a commit that reviews as "no functional change" and is therefore rubber-stamped, which is the review posture you least want on the file that defines a boundary.
It is currently invisible on main, which makes it worse
Rust Quality (fmt, clippy) is skipped on main's own pushes (changed-area gating). CI Lite on 2c579afc6: 4 success, 9 skipped, one unrelated frontend failure. So the gate is red but unexercised on main, and the next Rust-touching PR is the one that wears it — it looks like that PR's fault. This is the same dynamic as #6451 and #6486: breakage that accumulates behind a lane that does not run.
Two further gates are in the same state on 2c579afc6 and are worth separating from this one:
Solution (optional)
Keep the intent, drop the line from the identity. Options, cheapest first:
- Key on
rule\0path\0text\0occurrence and carry line as advisory metadata, refreshed silently. A genuinely new violation still fails; a pure move does not. The "moved violation" concern is largely served by occurrence already.
- Key on line but report a move as a distinct, non-failing class ("N violations moved; baseline refreshed"), failing only on added/removed.
- If physical location must stay load-bearing, add
--refresh-lines that rewrites only line numbers for otherwise-identical entries, so the routine case is mechanical and a real change still needs review.
I'd take (1): it makes the gate fail on what it is named for — the ownership boundary changing — rather than on unrelated churn.
Acceptance criteria
Related
#6462 (the re-baseline this outlived by six hours), #6451 (failing step hides later steps), #6486 (same lane, same invisibility), #6310 (the layout gate's pinned limits).
Found while separating inherited red from my own on #6517/#6488 — both are comment-only or test-only and reproduce this failure byte-identically against a pristine main tree.
Summary
The agent-runtime ownership boundary gate keys each baselined violation on its line number, so an edit that merely shifts lines in a file containing a violation reddens the gate — reporting the same code as both a new "unbaselined violation" and a "stale baseline entry". Main is red on this right now, one day after #6462 re-baselined it, with zero actual change to the set of violations.
Proof: the violation set is identical, only lines moved
Regenerating the baseline from current
main(2c579afc6) and comparing against the committed one:Zero difference once the line number is excluded. Same rules, same paths, same source text, same occurrence counts. Examples of entries whose only change is the line:
That is why the failure output lists the same lines on both sides — every "unbaselined violation" is also a "stale baseline entry".
Mechanism
scripts/ci/check-agent-runtime-boundary.mjs:341:Membership is then exact-JSON set comparison (
:365-367), so a one-line shift is indistinguishable from "old violation deleted + new violation added".The comment shows this is deliberate, and the intent is sound — a violation that moved should not be waved through unexamined. The cost may not have been weighed: the trigger is not "the violation changed", it is "any line above it changed". A PR that adds an import to
agent_chat.rsinherits a red gate for seven violations it never touched.Why this is worth fixing rather than re-baselining again
Re-baselining is not durable, and the history shows the treadmill:
180bec2f0656c80e58Under six hours. Each refresh is a commit that reviews as "no functional change" and is therefore rubber-stamped, which is the review posture you least want on the file that defines a boundary.
It is currently invisible on main, which makes it worse
Rust Quality (fmt, clippy)isskippedon main's own pushes (changed-area gating). CI Lite on2c579afc6: 4 success, 9 skipped, one unrelated frontend failure. So the gate is red but unexercised on main, and the next Rust-touching PR is the one that wears it — it looks like that PR's fault. This is the same dynamic as #6451 and #6486: breakage that accumulates behind a lane that does not run.Two further gates are in the same state on
2c579afc6and are worth separating from this one:cargo fmt --check—agent/harness/tool_result_artifacts/mod_tests.rs,agent/session_host/runtime_adapter_tests.rspnpm rust:layout—spawn_async_subagent_execute.rs(847/832),spawn_subagent_tool_impl.rs(803/796), both over their own pinned limits (cf. Rust layout gate: main is one line from red (two files at exactly 750, one legacy pin at 0), no warning band, and two gaps in the gate #6310)Solution (optional)
Keep the intent, drop the line from the identity. Options, cheapest first:
rule\0path\0text\0occurrenceand carrylineas advisory metadata, refreshed silently. A genuinely new violation still fails; a pure move does not. The "moved violation" concern is largely served byoccurrencealready.--refresh-linesthat rewrites only line numbers for otherwise-identical entries, so the routine case is mechanical and a real change still needs review.I'd take (1): it makes the gate fail on what it is named for — the ownership boundary changing — rather than on unrelated churn.
Acceptance criteria
maingreen on the boundary gate without a fresh re-baseline commit.Related
#6462 (the re-baseline this outlived by six hours), #6451 (failing step hides later steps), #6486 (same lane, same invisibility), #6310 (the layout gate's pinned limits).
Found while separating inherited red from my own on #6517/#6488 — both are comment-only or test-only and reproduce this failure byte-identically against a pristine
maintree.