feat(ci): ratchet raw repo connectionId host checks; migrate the cheap ones (#31096)

* feat(ci): ratchet raw repo connectionId host reads; one drop-in resolver

Codex review 6 class fix (#4/#6/#7): host decisions read off a repo row's
legacy connectionId miss rows that name SSH only as executionHostId.

- getRepoRoutingConnectionId (shared/execution-host.ts): drop-in for a raw
  repo.connectionId routing check that also finds executionHostId-only SSH.
- check-repo-host-read-ratchet: per-file count of raw repo connectionId
  reads in src/main, src/shared, src/cli; counts may only shrink.
- Migrated 66 cheap reads: runtime GitHub/GitLab commands, PR/MR head ref
  fetches, preserved-branch cleanup, ref queries, base-ref IPC, worktree
  preparation, trash sweep, scan cache TTL, usage metadata.

* fix(ipc): PR base IPC routes executionHostId-only SSH rows; ratchet is a stated lower bound

Review follow-up (Opus on #31096):
- worktrees:resolvePrBase decided git/gh routing on the raw connectionId while
  its head-ref fetches already used the resolver; one resolved connectionId
  now drives all of it (test fails on main).
- getRepoRoutingConnectionId's contract is stated exactly: never local when the
  raw field is set; on a contradictory ssh row executionHostId wins.
- The ratchet regex no longer matches report.connectionId; header and docs
  say it is a lower bound.
- Regression tests for a runtime GitHub and GitLab command site.

* test(ci): pin the repo host-read ratchet step to the static phase

* fix(ci): repo host-read ratchet skips verbatim field copies into projected rows

A copy of connectionId into a projected row decides nothing; migrating it to
the resolver would change what the projection publishes. The sidebar feed
catalog's copy (added after the baseline) and two older projections no longer
count; baseline pruned to 91.
This commit is contained in:
Neil
2026-10-20 14:00:32 -07:00
committed by GitHub
parent 8a4ef49a4d
commit 12bf32836b
27 changed files with 478 additions and 79 deletions
@@ -10,6 +10,7 @@ import {
createIssue,
updateIssue
} from '../github/client'
import { getRepoRoutingConnectionId } from '../../shared/execution-host'
type LocalGitArgs = [] | [LocalProjectGhExecOptions]
@@ -33,7 +34,7 @@ export class RuntimeGitHubIssueCommentCommands {
title,
body,
repo.issueSourcePreference,
repo.connectionId ?? null,
getRepoRoutingConnectionId(repo),
fields,
...this.deps.getLocalGitArgs(repo)
)
@@ -49,7 +50,7 @@ export class RuntimeGitHubIssueCommentCommands {
repo.path,
number,
updates,
repo.connectionId ?? null,
getRepoRoutingConnectionId(repo),
this.deps.getLocalGitArgs(repo)[0],
repo.issueSourcePreference
)
@@ -67,7 +68,7 @@ export class RuntimeGitHubIssueCommentCommands {
repo.path,
number,
body,
repo.connectionId ?? null,
getRepoRoutingConnectionId(repo),
prRepo ?? null,
this.deps.getLocalGitArgs(repo)[0],
// Why: the issue source selector only scopes issues; PR comments keep their resolution.
@@ -82,7 +83,7 @@ export class RuntimeGitHubIssueCommentCommands {
const repo = await this.deps.resolveRepo(repoSelector)
return addPRReviewComment({
repoPath: repo.path,
connectionId: repo.connectionId ?? null,
connectionId: getRepoRoutingConnectionId(repo),
localGitOptions: this.deps.getLocalGitArgs(repo)[0],
...args
})
@@ -109,7 +110,7 @@ export class RuntimeGitHubIssueCommentCommands {
args.threadId,
args.path,
args.line,
repo.connectionId ?? null,
getRepoRoutingConnectionId(repo),
args.prRepo ?? null,
...this.deps.getLocalGitArgs(repo)
)