Centralize repository identity resolution#227
Conversation
roborev: Combined Review (
|
|
Why do we support anything other than repoLookupRequireUnambiguousOwnerName at all? feels like we can correctly determin the correct name for things at all times, so no guessing should be needed here. |
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
10d8d76 to
ee2ee78
Compare
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
Repository host, owner/name fallback, ambiguity, not-found, and item-number lookup rules were spread across route helpers and handlers, which made each caller decide a slightly different slice of repository identity semantics. This deepens the backend module boundary so handlers resolve a repo once, then use stable repo IDs for pull request and issue item lookups. The result keeps same owner/name rows across hosts from leaking through item resolution and gives mutations one place to enforce platform_host when owner/name is ambiguous, improving calling uniformity for repo-bound handlers. Validation: go test ./internal/db -shuffle=on; go test ./internal/server -run 'TestRepositoryIdentity|TestAPICreateIssue|TestAPIResolveItem|TestAPISetStarred|TestAPIUnsetStarred|TestAPIGetIssue|TestAPIPostIssueComment|TestAPIEditIssueComment|TestAPIListPullsAcceptsHostQualifiedRepoFilter' -shuffle=on; git diff --check. Full go test ./internal/server -shuffle=on was attempted and failed in unrelated tmux process-leak stress coverage under host process pressure. Co-authored-by: OpenAI Codex <noreply@openai.com>
Owner/name repo lookup now has one rule: it succeeds only when the tuple is unambiguous, otherwise callers must provide platform_host. This removes the permissive lookup mode and keeps host selection explicit across item resolution and generated clients. Validation: go test ./internal/server -run 'TestResolveItem_(PR|Issue|AmbiguousOwnerNameRequiresPlatformHost|ExplicitPlatformHostResolvesRepoScopedItem|UntrackedRepo|NotFoundOnGitHub|GitHubServerError)$|TestRepositoryIdentity' -shuffle=on; go test ./internal/github -shuffle=on.
Resolve item now checks configured repo ambiguity before falling through to no-host sync, so duplicate owner/name repos cannot be silently resolved via hostFor. Issue routes also map ambiguous repo input to 400 and the context doc records the strict identity rule.
Repository identity resolution now lives in internal/repoidentity with a small persistence interface and package-level tests. The server keeps only route-shape adapters, so ambiguity, not-found handling, and repo-id item lookup have one shared implementation.
Prevent ready-for-review, workflow approval, merge, and issue sync paths from choosing the first tracked host when owner/name is ambiguous. Host-qualified PR actions now use host-specific syncer helpers and the API spec exposes platform_host on the affected mutation routes.\n\nVerified with:\n- GOCACHE=/tmp/middleman-gocache go test ./internal/server -run 'Test(API(SyncIssueRejectsAmbiguousTrackedRepoBeforeSync|MergePRRejectsAmbiguousRepoBeforeMutation|MergePRUsesPlatformHostQuery|ReadyForReviewRejectsAmbiguousRepoBeforeMutation)|ResolveItem_(AmbiguousOwnerNameRequiresPlatformHost|AmbiguousTrackedRepoRequiresPlatformHostBeforeSync|ExplicitPlatformHostResolvesRepoScopedItem))' -shuffle=on\n- GOCACHE=/tmp/middleman-gocache go test ./internal/github -shuffle=on\n- git diff --check\n\nFull internal/server shuffle was attempted but hit unrelated resource-sensitive tmux/workspace failures in the test environment.
Thread platform_host through PR route state, detail loads, action requests, and markdown item references so ambiguous owner/name repos keep their selected host across mutations. Resolve PR repo identity before GitHub mutations and add Playwright coverage for host-qualified PR ready, workflow approval, merge, and item-reference resolution flows. Verified with: bun run typecheck (packages/ui); bun run typecheck (frontend); bun run test src/ReadyForReviewButton.test.ts src/ApproveWorkflowsButton.test.ts; bun run test:e2e:mock tests/e2e/host-qualified-pr-actions.spec.ts; go test ./internal/server -run TestWorkspacePRDetailPlatformHost|TestAPI... -shuffle=on; go test ./internal/github -shuffle=on; git diff --check
Preserve platform_host for PR selections in the Activity drawer URL state so duplicate detail loads dedupe under the same host-qualified identity. Update ready-for-review e2e assertions to expect the host-qualified mutation URL now emitted by the PR action controls. Verified with: bun run typecheck (frontend); bun run test src/lib/utils/activitySelection.test.ts src/ReadyForReviewButton.test.ts src/ApproveWorkflowsButton.test.ts; bun run test:e2e tests/e2e-full/activity-drawer.spec.ts --project=chromium -g 'duplicate load stalls'; bun run test:e2e tests/e2e-full/detail-action-buttons.spec.ts --project=chromium -g 'ready for review updates API state|self-contained actions close'; git diff --check
Require ambiguous PR detail and approval requests to resolve repository identity before mutation, and thread platform_host through the approve UI and PR item-reference navigation. Verified with: - go test ./internal/server -run 'TestAPI(GetPullAmbiguousOwnerNameRequiresPlatformHost|GetPullUsesPlatformHostQuery|ApprovePRRejectsAmbiguousRepoBeforeMutation|ApprovePRUsesPlatformHostQuery)$' -shuffle=on - go test ./internal/server -run 'Test(API(GetPullAmbiguousOwnerNameRequiresPlatformHost|GetPullUsesPlatformHostQuery|ApprovePRRejectsAmbiguousRepoBeforeMutation|ApprovePRUsesPlatformHostQuery)|WorkspacePRDetailPlatformHost)$' -shuffle=on - bun run test src/ApproveButton.test.ts src/lib/utils/itemRefHandler.test.ts - bun run test:e2e:mock tests/e2e/host-qualified-pr-actions.spec.ts --project=chromium - bun run typecheck - bun run build - git diff --check Note: go test ./internal/server -shuffle=on also hit an unrelated tmux stress/process-limit failure in TestWorkspaceListTmuxActivityStressDoesNotLeakProcesses. 🤖 Generated with [OpenAI Codex](https://openai.com/codex) Co-authored-by: OpenAI Codex <noreply@openai.com>
Add platform_host to the kanban state endpoint and preserve host identity through PR detail, drawer, and board kanban update flows so duplicate owner/name repositories update the intended row. Verified with: - go test ./internal/server -run 'TestAPISetKanbanState|TestAPISetKanbanStateRejectsInvalidStatus|TestAPISetKanbanStateRejectsAmbiguousRepo|TestAPISetKanbanStateUsesPlatformHostQuery' -shuffle=on - bun run test src/lib/stores/detail-comment.svelte.test.ts - bun run typecheck - bun run test:e2e:mock tests/e2e/host-qualified-pr-actions.spec.ts --project=chromium - bun run build - git diff --check 🤖 Generated with [OpenAI Codex](https://openai.com/codex) Co-authored-by: OpenAI Codex <noreply@openai.com>
Reject ambiguous PR routes before mutating GitHub, carry platform_host through comments, state changes, content edits, starring, and diff reads, and keep generated markdown item refs distinct from sanitized raw HTML. Verified with: - go test ./internal/server -shuffle=on - bun run typecheck - bun run test src/lib/stores/detail-comment.svelte.test.ts src/lib/utils/itemRefHandler.test.ts src/lib/stores/diff.svelte.test.ts src/lib/stores/diff-scope.test.ts - bun run test:e2e:mock tests/e2e/host-qualified-pr-actions.spec.ts --project=chromium - bun run build - git diff --check Note: npx @sveltejs/mcp@0.1.22 svelte-autofixer packages/ui/src/components/detail/PullDetail.svelte --svelte-version 5 hung and was stopped. 🤖 Generated with [OpenAI Codex](https://openai.com/codex) Co-authored-by: OpenAI Codex <noreply@openai.com>
Update CommentBox persistence expectations for the platform_host argument now passed through PR comment submission. Verified with: - bun run test src/lib/components/detail-comment-persistence.test.ts - bun run typecheck - git diff --check 🤖 Generated with [OpenAI Codex](https://openai.com/codex) Co-authored-by: OpenAI Codex <noreply@openai.com>
Allow e2e state-change route mocks to match platform_host query strings so failure-path tests do not fall through and mutate the shared backend state. Verified with: - bun run test:e2e tests/e2e-full/detail-action-buttons.spec.ts tests/e2e-full/activity-drawer.spec.ts --project=chromium - git diff --check 🤖 Generated with [OpenAI Codex](https://openai.com/codex) Co-authored-by: OpenAI Codex <noreply@openai.com>
Install the PR files route before opening the detail view so the diff summary test intercepts the host-qualified files request instead of racing the real endpoint.\n\nVerified with:\n- bun run test:e2e tests/e2e-full/pr-detail-branches.spec.ts --project=chromium\n- git diff --check\n\n🤖 Generated with [OpenAI Codex](https://openai.com/codex)\nCo-authored-by: OpenAI Codex <noreply@openai.com>
Resolve issue state changes from the query platform_host used by generated clients, while preserving the legacy body fallback. Reject unqualified repo lookups when configured tracked repositories are ambiguous even if SQLite currently has only one matching row, preventing maintainer mutations from guessing a host.\n\nVerified with:\n- go test ./internal/server -run 'TestAPISetIssueStateUsesPlatformHostBody|TestAPISetIssueStateUsesPlatformHostQuery|TestAPIApprovePRRejectsAmbiguousRepoBeforeMutation|TestAPIApprovePRRejectsAmbiguousTrackedRepoBeforeMutation' -shuffle=on\n- go test ./internal/server -shuffle=on\n- git diff --check\n\n🤖 Generated with [OpenAI Codex](https://openai.com/codex)\nCo-authored-by: OpenAI Codex <noreply@openai.com>
roborev: Combined Review (
|
202cade to
99a04cd
Compare
Remove a one-use helper and keep the issue state platform_host fallback visible at the handler call site. Behavior is unchanged: query platform_host still wins, with the body value retained as compatibility fallback.\n\nVerified with:\n- go test ./internal/server -run 'TestAPISetIssueStateUsesPlatformHostBody|TestAPISetIssueStateUsesPlatformHostQuery|TestAPIApprovePRRejectsAmbiguousRepoBeforeMutation|TestAPIApprovePRRejectsAmbiguousTrackedRepoBeforeMutation' -shuffle=on\n- git diff --check\n\n🤖 Generated with [OpenAI Codex](https://openai.com/codex)\nCo-authored-by: OpenAI Codex <noreply@openai.com>
roborev: Combined Review (
|
Move platform_host off JSON mutation query parameters and into required request body fields so repository identity is carried with the payload. Regenerate API clients and update host-qualified UI actions to send the new shape. Verified with: - go test ./internal/server -run 'TestAPI(SetKanbanState|SetIssueState|ApprovePR|MergePR|EditPR|EditPrComment|EditIssueComment|PostPrComment)' -shuffle=on - bun run typecheck - bun run test src/ApproveButton.test.ts src/ReadyForReviewButton.test.ts src/ApproveWorkflowsButton.test.ts src/lib/stores/detail-comment.svelte.test.ts - bun run test:e2e:mock tests/e2e/host-qualified-pr-actions.spec.ts --project=chromium - git diff --check Note: go test ./internal/server -shuffle=on still fails in TestWorkspaceListTmuxActivityStressDoesNotLeakProcesses due to a tmux/process stress violation unrelated to this API contract change. 🤖 Generated with [OpenAI Codex](https://openai.com/codex) Co-authored-by: OpenAI Codex <noreply@openai.com>
Centralize repeated lookup and scanning paths that grew while adding host-qualified repository identity. This keeps the behavior anchored in one place so future host-aware actions are less likely to drift in status mapping, tracked-repo checks, or merge-request row scans.\n\nValidation:\n- go test ./internal/db ./internal/github ./internal/server -shuffle=on\n- git diff --check Generated with OpenAI Codex Co-authored-by: OpenAI Codex <noreply@openai.com>
Host-qualified repository identity needs to hold beyond API calls. Duplicate repos with the same owner/name/number could be shown as the same selected activity item or collapsed into one commit run when only the platform host distinguished them.\n\nThe tests now use duplicate-host examples that fail if PR selection, commit-run collapse, or item-ref navigation drops platform_host.\n\nValidation:\n- bun run --cwd frontend typecheck\n- bun run --cwd frontend test ../packages/ui/src/components/ActivityFeed.test.ts ../packages/ui/src/components/activityRows.test.ts src/lib/utils/itemRefHandler.test.ts\n- git diff --check Generated with OpenAI Codex Co-authored-by: OpenAI Codex <noreply@openai.com>
Repository identity is platform_host plus owner/name, so the repoidentity module should never perform hostless owner/name guessing. Server handlers now derive a concrete host from unambiguous tracked configuration before calling the module and reject ambiguous hostless mutations before side effects.\n\nThis closes the configured-but-not-yet-synced ambiguity path for create-issue and starred actions, where a single local SQLite row could previously hide multiple tracked repos sharing owner/name.\n\nValidation:\n- go test ./internal/repoidentity ./internal/server -run 'TestLookupRepoRequiresPlatformHost|TestRepositoryIdentityRequiresPlatformHost|TestAPICreateIssueRejectsAmbiguousTrackedRepoBeforeMutation|TestAPISetStarredRejectsAmbiguousTrackedRepo|TestAPICreateIssueUsesPlatformHost|TestAPISetStarred$|TestAPIUnsetStarred|TestResolveItem' -shuffle=on\n- go test ./internal/repoidentity ./internal/server -run 'TestRepositoryIdentity|TestLookup|TestResolveLocalItem|TestGetIssue|TestAPI(GetPull|SetKanbanState|ReadyForReview|ApprovePR|MergePR|SetPRGitHubState|SetIssueGitHubState|CreateIssue|SetStarred|UnsetStarred|PostPrComment|EditPrComment|EditPRContent|ResolveItem)' -shuffle=on\n- go test ./internal/repoidentity ./internal/server -short -shuffle=on\n- git diff --check\n\nNote: full go test ./internal/server -shuffle=on currently fails in TestWorkspaceDeleteDirtyKeepsRuntimeSessionsE2E, an existing workspace runtime test unrelated to repository identity. Generated with OpenAI Codex Co-authored-by: OpenAI Codex <noreply@openai.com>
roborev: Combined Review (
|
Ready-for-review now carries platform_host in the mutation body. The full-stack action-menu tests were still waiting for a query parameter, so CI could miss the actual host-preservation contract and time out on the response matcher.\n\nValidation:\n- bun run --cwd frontend test:e2e tests/e2e-full/detail-action-buttons.spec.ts --project=chromium -g 'self-contained actions close|ready for review updates API state'\n- git diff --check Generated with OpenAI Codex Co-authored-by: OpenAI Codex <noreply@openai.com>
roborev: Combined Review (
|
Raw markdown HTML should not be able to opt into Middleman item-reference navigation by forging data-middleman-item-ref. Generated item refs now carry a per-render internal token through sanitization, and only those anchors receive the trusted marker after raw HTML has been scrubbed.\n\nValidation:\n- bun run --cwd frontend typecheck\n- bun run --cwd frontend test ../packages/ui/src/utils/markdown.test.ts src/lib/utils/itemRefHandler.test.ts\n- git diff --check Generated with OpenAI Codex Co-authored-by: OpenAI Codex <noreply@openai.com>
roborev: Combined Review (
|
Summary
How this makes the code better