Skip to content

[factory] relayfile-cloud#159's app-actor GitHub read shipped; Factory has no caller, private-repo issues still resolve indeterminate #449

Description

@khaliqgant

The server side of #228/relayfile-cloud#159 shipped; Factory has no caller

relayfile-cloud#159 ("Mount-native app-actor GitHub read: let a caller request a read as the App installation") closed COMPLETED on 2026-09-02, shipped in relayfile-cloud PR #160. It adds POST /v1/workspaces/:workspaceId/github/repos/:owner/:repo/issues/:number/read with body {"actor":"app"}, requires fs:read scope, and returns the exact three-outcome shape Factory already knows how to consume:

type GithubIssueLookup =
  | { outcome: "found"; issue: GithubConnectionIssue }
  | { outcome: "not-found" }
  | { outcome: "indeterminate"; reason: string }

(relayfile-cloud packages/relayfile/src/writeback/providers/github.ts:70-73)

Factory's consumer side was deliberately left unwired pending this — see src/writeback/github.ts:100-103:

Provider-authoritative reads remain intentionally absent until the mount exposes an app-actor read contract; GithubWriteback models those as optional.

That contract now exists. Factory doesn't call it. src/mount/relayfile-cloud-mount-client.ts:381 still unconditionally constructs the unauthenticated reader:

this.githubRead = new GithubApiIssueRead()

GithubApiIssueRead (src/mount/github-api-issue-read.ts) sends no Authorization header by design (that invariant is correct and stays — see #228). Its consumer, #readGithubIssue at src/orchestrator/factory.ts:7554-7584, already branches on lookup.outcome in the exact shape the new route returns (:7584-7600). So every private-repo issue Factory tries to read through the API fallback still resolves indeterminate today, even though the mount-native authenticated path that would resolve it found/not-found has been live for a day.

This is a merged capability with no caller — inert until wired.

Fix shape (matches the shape proposed and left un-actioned on #228, now unblocked)

  1. Add a GithubConnectionRead implementation that calls the new mount route with actor: "app" instead of GitHub directly — same call pattern relayfile-github-connection-write.ts already uses for author: 'app' writes (mount-native, no local credential).
  2. Wire relayfile-cloud-mount-client.ts:381 to use it. Whether the existing unauthenticated GithubApiIssueRead stays as a fallback for unconfigured/non-cloud deployments, or is retired outright now that the mount fulfills reads server-side unconditionally, is an open call for whoever picks this up — the mount route requires no deployment-side credential, so there may be no case left that needs the unauthenticated fallback.
  3. Preserve the three outcomes exactly — do not collapse indeterminate into found/not-found. factory.ts:7590-7600's handling of indeterminate (counts githubIssueUnverifiable, does not promote to found) must keep working against the new reader's indeterminate responses (5xx/timeout at the mount, or a repo the App genuinely can't see).

Definition of done

  • Unit test: a private-repo issue lookup resolves outcome: 'found' through the new App-actor route (mock the mount response).
  • Must-not-fire: a mount not-found still resolves not-found; a mount indeterminate still resolves indeterminate and still increments githubIssueUnverifiable — do not regress #228's must-not-fire test.
  • Negative-auth arm not required here (the mount owns credential handling now); a fetch/mount-error path must still map to indeterminate, not not-found or a thrown error that skips the issue silently.
  • Confirm against a real private repo issue if a live credentialed workspace is reachable from the test/dev environment; otherwise a stubbed mount response is sufficient and should be flagged as such.

Related: #228 (design note, Axis B ruling), relayfile-cloud#159 (server side, closed).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions