pr-merge.sh: main-only hardcode blocks every next-lane merge (wrapper policy predates next pivot) #1132

Open
opened 2026-08-09 10:42:06 +00:00 by mos-dt-0 · 1 comment
Collaborator

pr-merge.sh:97 refuses any PR whose base is not main:

Error: Mosaic policy allows merges only for PRs targeting 'main' (found 'next').

The policy predates the next-lane pivot. Every next-base PR (#1109, #1127, #1129, #1130, and velma's #1131) is unmergeable through the sanctioned wrapper. The repo-local copy (packages/mosaic/framework/tools/git/pr-merge.sh) is byte-identical to the installed one. Chicken-and-egg: the fix PR itself (base next) cannot merge through the wrapper.

Observed live 2026-08-09: velma's #1131 hit it after every readiness gate passed; she failed closed correctly (no raw API, no wrapper patching) and escalated. fred executed the merge orchestrator-side via provider API with pinned head_commit_id as the interim mechanism.

Fix shape:

  • Allow-listed merge bases (main, next) — hardcoded pair or read from repo/mosaic config; unknown repos stay fail-closed main-only.
  • Check the .ps1 twin for the same hardcode.
  • Red-first regression test (blocked-base still refuses; allow-listed base proceeds).
  • Installed copies are operator-applied (same protocol as #1129 — doers never hand-patch installed tools).

Until fixed: doers keep failing closed; next-lane merges route through the orchestrator.

`pr-merge.sh:97` refuses any PR whose base is not `main`: Error: Mosaic policy allows merges only for PRs targeting 'main' (found 'next'). The policy predates the next-lane pivot. Every next-base PR (#1109, #1127, #1129, #1130, and velma's #1131) is unmergeable through the sanctioned wrapper. The repo-local copy (`packages/mosaic/framework/tools/git/pr-merge.sh`) is byte-identical to the installed one. Chicken-and-egg: the fix PR itself (base next) cannot merge through the wrapper. **Observed live 2026-08-09:** velma's #1131 hit it after every readiness gate passed; she failed closed correctly (no raw API, no wrapper patching) and escalated. fred executed the merge orchestrator-side via provider API with pinned `head_commit_id` as the interim mechanism. **Fix shape:** - Allow-listed merge bases (`main`, `next`) — hardcoded pair or read from repo/mosaic config; unknown repos stay fail-closed main-only. - Check the `.ps1` twin for the same hardcode. - Red-first regression test (blocked-base still refuses; allow-listed base proceeds). - Installed copies are operator-applied (same protocol as #1129 — doers never hand-patch installed tools). Until fixed: doers keep failing closed; next-lane merges route through the orchestrator.
Author
Collaborator

Field report (sb-it-1-dt, 2026-08-09): the C2 install-ordering guard cannot reach Pi's enforcement wiring — three fleet agents bricked on first mutator.

Sequence: three pi-runtime fleet agents were provisioned via mosaic fleet add and launched via [email protected]. Every bash/write/edit call was denied MUTATOR_UNVERIFIED — pi's READ_ONLY_TOOLS is {read, grep, find, ls}, so the seats could not clone a repo or write a file. This is the expected consequence of #869's missing activation half (lease_promote.py docstring: begin_verification/observe_receipt/promote_lease have no production caller ⇒ no lease can reach VERIFIED).

The gap this adds to the record: install-ordering-guard.js (card C2) strips enforcement hooks from the claude settings.json path only. Pi enforcement is wired by runtime/pi/mosaic-extension.ts (pi.on('tool_call', … mutator-gate.py)) unconditionally — the C2 guard never sees it. Additionally, the C1 probe (leaseEnforcementActivatable()) reports TRUE on this host (CLI advertises the capability, daemon.py + launch-runtime.py resolve, socket resolves), so even a pi-side C2 equivalent keyed on C1 would have wired the gate: C1 measures that activation artifacts are present, not that any production caller actually drives promotion.

Interim applied on this host (operator-authorized, disclosed): the pi extension now skips wiring the tool_call gate iff an explicit operator marker file ~/.config/mosaic/fleet/allow-inactive-enforcement exists — mirroring C2's --allow-inactive-enforcement (marker file rather than env var; loud session-start warning; message_end observer and revoke hooks remain wired). To be reverted when the activation half from this issue ships.

Suggested for this issue's scope: (a) a pi-side wiring gate equivalent to C2, and (b) tightening C1 (or adding a C1b) so 'activatable' requires a resolvable production promotion caller, not just artifact presence.

**Field report (sb-it-1-dt, 2026-08-09): the C2 install-ordering guard cannot reach Pi's enforcement wiring — three fleet agents bricked on first mutator.** Sequence: three pi-runtime fleet agents were provisioned via `mosaic fleet add` and launched via `[email protected]`. Every `bash`/`write`/`edit` call was denied `MUTATOR_UNVERIFIED` — pi's READ_ONLY_TOOLS is `{read, grep, find, ls}`, so the seats could not clone a repo or write a file. This is the expected consequence of #869's missing activation half (`lease_promote.py` docstring: begin_verification/observe_receipt/promote_lease have no production caller ⇒ no lease can reach VERIFIED). The gap this adds to the record: `install-ordering-guard.js` (card C2) strips enforcement hooks from the **claude** `settings.json` path only. Pi enforcement is wired by `runtime/pi/mosaic-extension.ts` (`pi.on('tool_call', … mutator-gate.py)`) unconditionally — the C2 guard never sees it. Additionally, the C1 probe (`leaseEnforcementActivatable()`) reports TRUE on this host (CLI advertises the capability, daemon.py + launch-runtime.py resolve, socket resolves), so even a pi-side C2 equivalent keyed on C1 would have wired the gate: C1 measures that activation artifacts are *present*, not that any production caller actually drives promotion. Interim applied on this host (operator-authorized, disclosed): the pi extension now skips wiring the tool_call gate iff an explicit operator marker file `~/.config/mosaic/fleet/allow-inactive-enforcement` exists — mirroring C2's `--allow-inactive-enforcement` (marker file rather than env var; loud session-start warning; message_end observer and revoke hooks remain wired). To be reverted when the activation half from this issue ships. Suggested for this issue's scope: (a) a pi-side wiring gate equivalent to C2, and (b) tightening C1 (or adding a C1b) so 'activatable' requires a resolvable production promotion caller, not just artifact presence.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1132