You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Round-5 cold audits of the seven open #177 follow-up PRs (#179#180#181#182#183#186#188) found
that the PRs are individually reviewable but cannot be merged in arbitrary order. This issue
records the constraints, since staging has no branch protection (#185) and nothing mechanically
enforces ordering. Every claim below was produced by execution, not inspection.
Base for all measurements: origin/staging = 4a52ed4, verified merge-base for all seven PRs.
Heads: #179 98c9cd2 · #180 35e7975 · #181 59ead4d · #182 fb1e793 · #183 a93d51f · #186 3ade3fa · #188 1e152fc.
This repo allows all three merge strategies (squash, merge, rebase all true), so conflicts
were swept under both merge-commit and squash topologies — they differ, and one conflict appears only
under squash.
Conflict matrix (executed via git merge-tree --write-tree)
Both PRs rewrite the same credential surface and both edit the same two auth test modules, so the
safety net is being merged at the same time as the code it guards:
Whichever lands second has to re-derive the other's credential model by hand, inside the auth path. Sequence them and rebase the second on the first before either merges.
There is also a perverse coupling between them. #186 removes the shipped MCP default; the
reserved-name refusal that stops ensure_service_user from retargeting the human admin row exists
only in #188 (_RESERVED_HUMAN_USERNAMES, absent from #186). Since the chart still ships mcpUsername: admin, closing #186's wiring gap without #188's guard present makes ensure_service_user rewrite the human admin row. These two need to land together, or #186 needs the
refusal back.
#183 × #186 — a semantic conflict, not just a textual one
#183 adds install-guide text instructing the operator to keep the shipped default:
"(the default MCP_USERNAME is admin, whose initial password is changeme). Leave it at changeme for the first boot so it matches the seeded admin account"
#186 removes that default outright ("No default password ships"; read /app/keys/initial_admin_password). If #183 lands after #186, the customer-facing guide walks the
operator into a credential that no longer exists and the MCP client 401s. Resolving the install-guide.html conflict by picking hunks will not surface this. The stated intent (#183 merges
with/after #186 + #188) is correct — it just isn't enforced anywhere.
For attribution, since an earlier round got this wrong: the changeme defaults pre-date this
series. At base, 4a52ed4:backend/core/config.py:101,103 and 4a52ed4:helm/bnk-forge/values.yaml:29 already carry them, and git diff 4a52ed4 <pr-183-head> -- backend/core/config.py helm/bnk-forge/values.yaml is empty. #183
does not introduce the exposure; it documents it. #186 is the PR that removes it.
#180 × #182 — squash-only, and #182 ships the older copy
Both branches addscripts/sync-version-artifacts.sh with different content: #180's is 154
lines, #182's is 66 (182-line diff between them). #182's copy is the pre-fix variant carrying the grep -m1-reader-vs-global-sed-writer bug, with no empty-VERSION guard, no vacuity floor, no
operator chart and no --list. Clean as a merge commit (the merged blob is #180's version); add/add
conflict under squash.
Simplest fix: drop the file from #182 and let #180 own it, since it is #180's stated deliverable.
#181 × #182 — and a gate that blocks its own sibling
They conflict on release.yml under both strategies. Worse, #182's new commit-lint gate rejects
two of #181's commits outright (they carry a literal [skip ci] in the body). And if #181 were
squash-merged anyway, the squash body carries the marker, so GitHub suppresses every workflow for
that push — no CI run, no Release run, release silently starved.
Independently: #182's commit-lint also rejects 4a52ed4 itself — a GitHub-composed squash commit
that is the current tip of staging, an ancestor of main, and unamendable. That is tracked in the #182 review comment; it blocks #182 regardless of ordering.
Clean — no action needed
Alembic migration heads. Only #188 adds revisions (v2_154 → v2_155, chained off the staging
head v2_153); no revision-id collision with any sibling PR, and no PR edits an existing migration
file in place (--diff-filter=M over alembic/versions is empty across all seven). Single head
preserved.
Round-5 cold audits of the seven open #177 follow-up PRs (#179 #180 #181 #182 #183 #186 #188) found
that the PRs are individually reviewable but cannot be merged in arbitrary order. This issue
records the constraints, since
staginghas no branch protection (#185) and nothing mechanicallyenforces ordering. Every claim below was produced by execution, not inspection.
Base for all measurements:
origin/staging=4a52ed4, verified merge-base for all seven PRs.Heads:
#179 98c9cd2·#180 35e7975·#181 59ead4d·#182 fb1e793·#183 a93d51f·#186 3ade3fa·#188 1e152fc.This repo allows all three merge strategies (
squash,merge,rebaseall true), so conflictswere swept under both merge-commit and squash topologies — they differ, and one conflict appears only
under squash.
Conflict matrix (executed via
git merge-tree --write-tree).github/workflows/release.ymluser-pack/install-guide.htmlscripts/sync-version-artifacts.sh+ci.yml,release.yml,AGENTS.mdSquash was simulated by committing the squashed tree onto the base and merging the sibling, which is
what GitHub's squash button actually produces.
The blocking one: #186 × #188 (16 files)
Both PRs rewrite the same credential surface and both edit the same two auth test modules, so the
safety net is being merged at the same time as the code it guards:
Whichever lands second has to re-derive the other's credential model by hand, inside the auth path.
Sequence them and rebase the second on the first before either merges.
There is also a perverse coupling between them. #186 removes the shipped MCP default; the
reserved-name refusal that stops
ensure_service_userfrom retargeting the humanadminrow existsonly in #188 (
_RESERVED_HUMAN_USERNAMES, absent from #186). Since the chart still shipsmcpUsername: admin, closing #186's wiring gap without #188's guard present makesensure_service_userrewrite the human admin row. These two need to land together, or #186 needs therefusal back.
#183 × #186 — a semantic conflict, not just a textual one
#183 adds install-guide text instructing the operator to keep the shipped default:
#186 removes that default outright ("No default password ships"; read
/app/keys/initial_admin_password). If #183 lands after #186, the customer-facing guide walks theoperator into a credential that no longer exists and the MCP client 401s. Resolving the
install-guide.htmlconflict by picking hunks will not surface this. The stated intent (#183 mergeswith/after #186 + #188) is correct — it just isn't enforced anywhere.
For attribution, since an earlier round got this wrong: the
changemedefaults pre-date thisseries. At base,
4a52ed4:backend/core/config.py:101,103and4a52ed4:helm/bnk-forge/values.yaml:29already carry them, andgit diff 4a52ed4 <pr-183-head> -- backend/core/config.py helm/bnk-forge/values.yamlis empty. #183does not introduce the exposure; it documents it. #186 is the PR that removes it.
#180 × #182 — squash-only, and #182 ships the older copy
Both branches add
scripts/sync-version-artifacts.shwith different content: #180's is 154lines, #182's is 66 (182-line diff between them). #182's copy is the pre-fix variant carrying the
grep -m1-reader-vs-global-sed-writer bug, with no empty-VERSIONguard, no vacuity floor, nooperator chart and no
--list. Clean as a merge commit (the merged blob is #180's version); add/addconflict under squash.
Simplest fix: drop the file from #182 and let #180 own it, since it is #180's stated deliverable.
#181 × #182 — and a gate that blocks its own sibling
They conflict on
release.ymlunder both strategies. Worse, #182's newcommit-lintgate rejectstwo of #181's commits outright (they carry a literal
[skip ci]in the body). And if #181 weresquash-merged anyway, the squash body carries the marker, so GitHub suppresses every workflow for
that push — no CI run, no Release run, release silently starved.
Independently: #182's
commit-lintalso rejects4a52ed4itself — a GitHub-composed squash committhat is the current tip of
staging, an ancestor ofmain, and unamendable. That is tracked in the#182 review comment; it blocks #182 regardless of ordering.
Clean — no action needed
Alembic migration heads. Only #188 adds revisions (
v2_154→v2_155, chained off the staginghead
v2_153); no revision-id collision with any sibling PR, and no PR edits an existing migrationfile in place (
--diff-filter=Moveralembic/versionsis empty across all seven). Single headpreserved.
Suggested merge order
sync-version-artifacts.sh) — after fixing its check/write scope divergencecommit-lintbase-commit blocker fixed[skip ci]markers removed from commit bodiesMCP_PASSWORDguidance rewritten to the post-Stop shipping a default admin credential; generate it and enforce rotation #186 realityMerge-commit strategy avoids the #180 × #182 add/add; squash does not. If squash is used, land #180
before #182 and rebase.