Repository navigation
feat(git): name connections with no handle from the provider - #692
Conversation
Refs Paca-AI#661 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs Paca-AI#661 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Identities created by a plugin's data migration have an empty handle. When connections or shared identities are listed, ask providers that declare identity_description who they are and store the answer. Refs Paca-AI#661 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs Paca-AI#661 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A revoked token or a platform outage made every listing wait for the call again. Remember the failure in memory and skip the identity for 15 minutes. Refs Paca-AI#661 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only update rows whose handle is still empty, so a reconnect that named the identity meanwhile wins over a lazy describe. Zero rows is a no-op. Refs Paca-AI#661 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each nameless identity had its own 5 second timeout, so several unreachable ones could hold a listing for 5 seconds each, one after the other. Share the timeout across the listing and leave the rest for the next one, without a backoff since they were never asked. The logged error comes from the plugin, so mask it like any provider message. Refs Paca-AI#661 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cancel An ok answer with another ref or an empty handle now counts as a failure (logged, identity paused for 15 minutes) instead of clearing the backoff. A request cancelled by the client no longer pauses the identity; running out of the shared budget still does. Tests cover a real shared deadline over several identities and that the logged error is masked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
describe_identitySPI op:Capabilities.IdentityDescription, theDescribeIdentityRequestwire type andClient.DescribeIdentity, with the generated SPI copy, golden contract and docs (docs/plugins/git-provider-spi.md,docs/ai-agent/git-agent-workflow.md) kept in sync.- Lazy naming in listings:
ListIdentitiesandListConnectionsdescribe handle-less identities under one shared 5 s budget, best effort, and never fail the listing because of a provider. - Persisted profile: new
Store.UpdateIdentityProfilewrites the handle, and name/expiry when non-empty, only while the stored handle is empty, so a reconnect's handle is never overwritten. - Failure handling: a 15-minute in-memory backoff per identity after a provider error or an unusable answer (wrong
Ref.ID, empty handle), secrets masked viaRedactSecrets, and no backoff when the caller cancels. - Tests: unit coverage for the shared budget, backoff, caller-cancel, log masking and unusable answers; a client test and a Postgres-backed store test.
I read the full diff, traced the new code against the git_identities schema and the HTTP DTO, and ran go test, go test -race and go build ./... for the module — all pass. The shared-budget/context handling is sound (budget is a child of ctx, so the caller-cancel check cannot misfire on a budget timeout), s.mu is never held across provider or store calls, and the handle = '' guard matches the schema (no unique or check constraint on handle/display_name).
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
pikann
left a comment
There was a problem hiding this comment.
LGTM! Thanks so much for your contribution.
Could you please resolve the merge conflicts?
BTW, I've released Go SDK v0.4.2, so feel free to update the GitHub plugin for this as well
…ntity # Conflicts: # services/api/internal/service/git/service_test.go
|
Thanks @pikann! Conflicts resolved (merged master, tests and lint green). I'll update the GitLab and GitHub plugins to v0.4.2 next. |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
The only commit since the prior pullfrog review is a merge of upstream/master (92fe79bb) that resolves the conflicts the maintainer requested; the feature's own code is unchanged.
- Merge of
upstream/master:92fe79bbintegrates master (b0c4dd3, incl. the repository picker and issue listing). The conflict sites —spi_types.go,spi_wiretypes.go,service.go,service_test.go,client_test.goandwire-shapes.golden.json— carry both sides: this PR'sIdentityDescription/DescribeIdentityRequest/DescribeIdentityand upstream'sissue_list/ListIssuesRequest/IssuePage/ListRepositories. - No feature drift:
setup.go,describe_test.go,repository.goandgit_repository.goare untouched by the merge, so the describe path is byte-identical to what the prior review approved.
I verified the resolution: go build ./... and the full go test ./... for the module pass, the golden contract lists both identity_description and issue_list, and no conflict markers remain. The merge-order dependency on the SDK is now satisfied (v0.4.2 is released).
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Summary
When listing connections, core asks the provider who each identity without a handle is and stores the answer. Closes #661.
Why
Identities created by a plugin's data migration have no handle: they show a generic name and
@mentionsdo not match them until someone uses the token.Changes
describe_identityclient op, SPI types synced withscripts/sync-git-spi.sh.UpdateIdentityProfilenever overwrites an existing handle.docs/plugins/git-provider-spi.mdanddocs/ai-agent/git-agent-workflow.md.Tests
-race(about 3274 test results),go vetand golangci-lint clean; every commit builds. Unit tests cover the shared 5 s deadline over several identities, the backoff after unusable answers, no backoff on caller cancel, and that the logged error is masked.8a77ef9c(before the shared budget and the log masking, which are covered by unit tests only), with a mock GitLab/GitHub and data seeded in the old plugin tables: names appear after the migration on first listing for GitLab and GitHub; a 401 and a 503 keep the generic name, make one call each and none on later listings; a restart retries and the recovered host gets its name. No token in the logs.TestGitStore_UpdateIdentityProfile(the SQL guardAND handle = '') needsPACA_TEST_PG_DSNand is skipped in CI, so CI does not guard it; run it locally with a Postgres DSN.Dependency and merge order
No Go dependency on the SDK: core keeps its own copy of the wire types. Merge after Paca-AI/plugin-sdk-go#17 so the copy matches a released SDK. Providers that do not declare
identity_descriptionnever receivedescribe_identity(the existingdescribeop is still called as before). Then the GitLab and GitHub plugin PRs (opened once the SDK is tagged).🤖 Generated with Claude Code