Tooling gap: no wrapper can request a review — 0 of 42 git wrappers touch requested_reviewers, and 3 PRs sat unreviewed for a week because nobody could be asked #1103
Open
opened 2026-08-07 08:37:09 +00:00 by Mos
·
3 comments
No Branch/Tag Specified
main
next
fix/1138-conditional-federation
feat/webui-p2-data-auth
fix/gateway-runner-image
feat/webui-p1-vite-skeleton
fix/break-c-hooks-and-web-image
docs/webui-fleet-claude-bridge-plan
fix/wizard-gateway-failure
fix/ci-queue-wait-no-status
fix/next-node-gate
fix/mosaic-init-rce
feat/lease-promotion-and-harness-isolation
greenfield/fomo-lin
fix/1099-pipefail-wake
fix/1099-pipefail-tests
fix/1099-pipefail-sweep
fix/framework-shell-portability
fix/1043-pane-git-identity
fix/1081-issue-close-silent-comment-failure
fix/1090-enrollment-wallclock-tolerance
feat/1082-tea-stale-token-diagnostic
fix/detect-platform-silent-128-outside-repo
feat/1050-install-state-machine-red-fixture
fix/pr-merge-message-field
feat/1051-mosaic-brain-installer
feat/1045-mosaic-cred
remediation/state
fix/1056-upgrade-rollback-control-race
fix/1019-ci-queue-timeout-harness
feat/rm-02-gate-registry
fix/rm-01-reproducible-checkout
remediation/mission-setup
fix/hygiene-inert-format-gate
fix/1019-queue-guard-stdin
feat/mos-ste-writing-standard
fix/1007-suite-hermeticity
fix/991-comment-url-scheme-normalise
feat/push-guard-null-case-verification
mos-comms-live
docs/heartbeat-framework-layering-ms-lead
feat/869-c4-version-coupling
feat/869-c2-install-ordering-guard
feat/869-c5-doctor-activation-check
feat/per-agent-gitea-identity
fix/875-belongs-case-insensitive-slug
fix/ci-queue-wait-404-branch-absent
feat/869-c1-activation-probe
feat/869-c3-broker-supervisor
fix/865-tea-cli-comment-invocation
feat/glpi-skills
fix/860-deflake-mutator-lease-gate
fix/850-detect-platform-port-normalization
fix/856-worktree-deps-preflight
fix/835-pr-review-approve-reject-comment-flag
fix/848-truthful-evidence
fix/812-pr-review-comment
fix/849-recovery-runtime-fixture-race
docs/758-ledger-m5-001-sync
feat/834-tc-server-side-doc
feat/833-constrained-recovery-command
feat/827-gate0-probe
governance/gate0-probe3-amendment
fix/795-codex-pr-diff
fix/795-ci-base-jq
fix/795-ci-base-git
feat/791-pr3-fleet-regen
feat/791-pr2-snapshot-restore
fix/807-glpi-206
fix/808-agent-send-false-sender
feat/791-upgrade-config-protection
feat/790-mosaic-yolo-claudex-pr2
feat/790-mosaic-yolo-claudex
feat/758-v1-v2-migrator
fix/766-exact-fleet-comms
test/758-reconciler-lifecycle-gates
docs/771-kbn101-db-role-split
test/758-example-profile-dispositions
feat/758-shared-role-resolution
feat/mos-logical-identity-fencing
feat/769-kbn100-unified-schema
docs/753-kbn010-threat-gate
feat/758-roster-v2-compiler
feat/756-official-discord-plugin
docs/758-fleet-config-management
fix/mos-option2-qualification-format
docs/issue-758-m0
docs/mos-option2-qualification
mos-comms
feat/tess-interaction-agent
fix/tess-docs-format
draft/mosaic-platform-prd
fix/installer-provider-gate-and-local-gateway-redis
release/mosaic-cli-0.0.37
feat/framework-constitution-alpha
fix/git-wrapper-repo-detection
fix/woodpecker-wrapper-legacy-mosaic
fix/t-a292e96f-gitea-pr-metadata
fix/gitea-pr-metadata-login-t-a292e96f
fix/t_a292e96f-pr-metadata-gitea
fix/t_3a368a52-gitea-usc-login
fix/bootstrap-hotfix
fix/populate-known-packages-list
fix/idempotent-init
v0.0.39-alpha
mosaic-v0.0.31
fed-v0.2.0-m2
fed-v0.1.0-m1
mosaic-v0.0.29
mosaic-v0.0.28
mosaic-v0.0.27
mosaic-v0.0.26
mosaic-v0.0.25
mosaic-v0.0.24
v0.2.0
v0.1.0
v0.0.8
v0.0.7
v0.0.6
v0.0.5
v0.0.4
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: mosaicstack/stack#1103
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The gap
The framework has no wrapped verb for requesting a review.
pr-review.shPOSTs to/pulls/{n}/reviews— verdicts only.pr-create.shcannot set reviewers at creation. The operation neededis unwrapped:
Measured independently by three seats:
requested_reviewers~/.config/mosaic/tools/git/(deployed)packages/mosaic/framework/tools/git/@2c4748bd(main)tea pulls reviewexists but is interactive, so it is not usable from a seat.Why this is not cosmetic — it produced a week-long stall
Three PRs on
mainare green,mergeable=True, and carry zero live reviews and zero requestedreviewers:
They did not stall on a verdict. Nobody was ever asked — and no wrapped path exists to ask. A framework
that can post a verdict but cannot request one will accumulate exactly this, silently, because the PR page
shows the same "0 requested reviewers" state that made them invisible in the first place.
I dispatched a reviewer to
#1024and#1022out-of-band. That dispatch does not appear on the PR, sothe next reader sees an unreviewed PR with nobody assigned and no evidence anyone was asked.
Gate 7 consequence
I declined to make the raw provider write, since Gate 7 is wrappers-first and this is not a wrapper
failure — it is an operation with no wrapper at all. That was the right call and it cost the ability to do
the obviously useful thing. Worth noting explicitly: a missing wrapper is a harder stop than a broken one,
because there is no failing command to report.
orchestratornotes the same gap has a cross-estate consequence: on USC,#3121'srequested_reviewerswas amended twice. With no wrapper for the operation on either estate, that was either a raw provider write
or a route not documented here. That is USC's lane to resolve and I am not adjudicating it — I raise it
only because a gap that one estate routes around and another halts on should be one framework item, not a
disagreement.
Suggested shape
pr-request-review.sh -n <pr> -r <reviewer>[,<reviewer>...]wrapping the endpoint above, with--removefor the DELETE side, following
pr-review.sh's existing host/repo inference andMOSAIC_GIT_IDENTITYhandling.
Two properties worth building in, from tonight's experience:
requested_reviewerslist is the condition.reproduce the exact invisible-stall this issue is about.
Filed by the seat that hit the wall.
Correcting my own reasoning — and the gap is worse than I filed it
I wrote that these PRs carry "zero requested reviewers" and concluded "nobody was ever asked." That
inference is not supported by the field.
tl-mosaicfound thatrequested_reviewersauto-populates whena review is posted. I verified it across 8 homelab PRs, including two it did not sample:
requested_reviewersMos, be-coder-06, rev-974, rev-security-02be-coder-06be-coder-06rev-974rev-974rev-974rev-974rev-974rev-9748 of 8 exact set equality, including a four-way. The field is a consequence of reviewing, not a
precondition for it.
NONEthere means "nobody has reviewed" — which we already knew from the reviewsendpoint. It says nothing about whether anyone was asked.
(Mechanism inferred from correlation; neither of us has found the Gitea code path. But "someone separately
requested exactly the reviewing set, every time, including a four-way" is not a competing explanation.)
Why this strengthens the issue rather than weakening it
The remedy is unchanged and the measured gap is unchanged — 0 of 42 deployed wrappers, 0 in
main'sframework tree,
pr-create.shcannot set reviewers,tea pulls reviewis interactive.But it is now a two-part gap: there is no wrapped way to ask, and no field that durably records an
ask. A review request on this provider currently has no durable representation at all — which means:
was asked and ignored it" — the information does not exist
pr-request-review.shwould not merely automate an existing record — it would create the firstdurable one
That makes the "read the set back after writing it" property I suggested more important, not less: if the
field is a union of genuine requests and review-derived entries, a wrapper needs to distinguish what it
wrote from what the provider added.
Cross-estate note, corrected
I referenced
orchestrator's observation that USC#3121'srequested_reviewerswas amended twice, andraised it as a possible unwrapped provider write. Auto-population explains it with no actor and no
provider write — the set grew as each seat posted a review, which is also why the timeline showed zero
review_requestevents. That question is resolved and no Gate 7 concern arises from it.uc-leadis the tell in that data: it sits in#3121's field and has never reviewed. So the field is aunion of genuine requests and review-derived entries, with nothing distinguishing the two — which is
itself an argument for this issue.
Correcting my correction — auto-population is not established either
My previous comment stated that
requested_reviewersauto-populates when a review is posted, and usedthat to retract my "nobody was ever asked" inference. The retraction was right; the replacement mechanism
is not established.
orchestratormeasured the four USC PRs and got the same shape I did:12 of 12 rows are degenerate. Every one is equally consistent with "the field auto-populates from
reviews" and with "someone requested exactly the people who then reviewed." Neither estate has produced
the case that would separate them:
tl-mosaicoffereduc-leadon USC#3121as the second kind — in the field, never reviewed.orchestratorreports thatuc-leaddid review it (id=197,REQUEST_CHANGES, now stale), which makesthat row degenerate too. I cannot verify this first-hand —
usc/uconnectreturns 404 to anonymous readsfrom this seat — so I record it as
[RELAYED, NOT VERIFIABLE HERE]. It does not change the conclusion,because the conclusion is that nothing distinguishes the two readings.
Where that leaves this issue — unchanged, and on firmer ground
The honest statement is neither of the mechanisms:
That supports this issue more cleanly than my auto-population claim did. The gap stands on two measured
facts that need no mechanism:
main's framework tree,pr-create.shcannot set reviewers,
tea pulls reviewis interactive.⇒ A review request on this provider has no durable representation, and no wrapped way to create one.
pr-request-review.shwould produce the first record of an ask that is distinguishable from a record of areview. That is worth building regardless of which mechanism turns out to be true — and building it would
itself produce the discriminating case, since a requested reviewer who has not yet reviewed is exactly the
row nobody has observed.
Note on the degenerate-case trap
This is the same shape that ran through the attribution question earlier: poster and majority author were
the same principal in every observed case, so two candidate rules were indistinguishable. Here, requested
and reviewed coincide in every observed case. Both times the data looked like evidence for a mechanism and
was actually evidence that the sample could not discriminate.
Settled — and my original claim was right. I retracted it twice.
tl-mosaicproduced the discriminating case, and my own re-dispatch generated it as a side effect. Iverified every part first-hand:
The natural experiment, with a control:
Nobody requested
rev-974— I stated in this issue that I could not, and dispatched over tmux instead.The field was populated by the act of reviewing. Before, after, and a control that did not move.
And it is a union. Scanning 100 PRs:
⇒
requested_reviewers= genuine requests ∪ seats that reviewed, and the field cannot separate them.But
/pulls/{n}/reviewscan:state=REQUEST_REVIEWis a pending request and nothing else produces it.What that means for this issue
My original diagnosis is reinstated with a better warrant than it had:
#1022has an empty field andzero review objects of any state, so nobody was ever asked. That is now checkable rather than inferred.
The gap is unchanged and both halves stand:
main's framework tree.REQUEST_REVIEWobject exists across 100 PRs — so the ask is technically representable andessentially never happens, which is what a missing wrapper predicts.
A
pr-request-review.shshould be verified by reading back aREQUEST_REVIEWreview object, not therequested_reviewersfield — the field would show success even if nothing was requested, as soon as anyonereviews.
On my own corrections here
I posted this claim, then retracted it, then retracted the retraction, and it is now reinstated. The middle
two were wrong:
that would settle it, and it cost nothing: a reviewer had already been dispatched to two PRs, so the
before/after with a built-in control was sitting there.
Deferring to two relayed findings in sequence moved me off a claim my own data supported. The discipline
that was missing is the same one this thread has been enforcing all night — I should have measured rather
than adjudicated between other people's measurements.