Smoke-15: QA's claim_review diff was `origin/master...origin/<branch>`
but origin/master in QA's clone was the STALE clone-time tip
(47c674d) — the three-dot diff spanned the whole session delta
(41 files / +2740) instead of the 1-line README change.
Two compounding causes:
- _default_branch_ref early-returns the ref NAME when origin/HEAD is
set (it was) WITHOUT fetching it, so the base stayed stale.
- Every fetch in the diff path ran unauthenticated; the repo is
private, so `git fetch` failed ("could not read Username for
github.com") and could never refresh the ref. (The documenter path
was correct only because #162 uses the PAT-injected
workspace.fetch_branch_for_inspection.)
Fix: new best-effort _token_for_branch resolves the project PAT
(None on any failure → degrades to unauth, never raises in the
evidence path). diff()/list_changed_files() thread it into
_resolve_head_ref + _resolve_diff_base, whose fetches now pass
token= (uses the existing _run_git http.extraheader Basic-auth
injection). _resolve_diff_base additionally re-fetches the resolved
default branch so the base is current even when origin/HEAD shortcut
skipped the fetch.
Smoke-14: QA's claim_review evidence had pr_diff_summary="" and
files_changed=[] on a PR with a real README change. Root cause: diff()
and list_changed_files() diffed against the bare local <branch_name>.
That ref only exists in the clone where the dev ran `git checkout -b`
at claim. QA / documenter / PM inspect from their OWN clones, where a
bare <branch_name> resolves refs/heads then refs/remotes/<name> but
NEVER refs/remotes/origin/<name> — so `git diff base...<branch>` had an
unresolvable HEAD and silently returned an empty diff (run with
check=False).
#161 previously fixed the BASE side (cell-PM parent never pushed → fall
back to default branch). This is the symmetric HEAD-side facet.
open_pr pushes the leaf branch, so origin/<branch> is the
workspace-independent source of truth. New _resolve_head_ref fetches the
branch and prefers the local branch (dev's own clone, unchanged
behaviour), falling back to origin/<branch> (QA/doc/PM clones), then the
bare name so the command stays well-formed. diff() and
list_changed_files() route through it; explicit base (incremental dev
path, base=HEAD~1) is preserved.
#160 — panel /roboco-logo.png "received null":
next/image optimizer fails for static public assets in Next.js
standalone mode. Added `unoptimized` to the sidebar logo Image so
it serves the static file directly (validated on panel rebuild).
#161 — QA/doc evidence pr_diff_summary empty:
A leaf dev branch's parent_branch_for is the cell-PM branch, which
is never pushed (only devs push their leaf branch). diff against a
non-existent origin/<parent> returned empty. Added
GitService._resolve_diff_base + _default_branch_ref + _ref_exists:
diff/list_changed_files fall back to the repo default branch
(origin/HEAD → master/main) when origin/<parent> is absent.
#162 — claim_doc_task BRANCH_MISMATCH loop:
The documenter's clone is separate from the dev's; the task branch
already existed (dev created it) so no checkout ran in the doc
workspace — roboco_docs_write / commit failed BRANCH_MISMATCH and
the doc looped. Fixes:
(a) new GitService.checkout_branch_in_agent_workspace; claim_doc_task
checks out the task branch into the doc clone (best-effort —
a checkout hiccup never fails the claim).
(b) BRANCH_MISMATCH remediate now lists all four role claim verbs
(i_will_work_on / i_will_plan / claim_doc_task / claim_review).
(d) give_me_work next-hint is role+status aware via _claim_verb_hint
(doc→claim_doc_task, qa→claim_review, pm→i_will_plan, else dev).
Facet (c) (i_am_blocked "Not Found" for doc) was only reachable via
the stuck-without-checkout path; primary fix removes it.
Smoke-11 reached dev→QA→doc (deepest ever) and validated the prior
6 fixes (panel flood gone, #158/#159/#157 confirmed). These three
clear the doc-phase blockers found in that run.