Skip to content

feat(proto): add ACCOUNT_TYPE_INVITATION to UserTrait.AccountType - #1102

Open
mstanbCO wants to merge 1 commit into
mainfrom
mstanbCO/add-invitation-account-type
Open

feat(proto): add ACCOUNT_TYPE_INVITATION to UserTrait.AccountType#1102
mstanbCO wants to merge 1 commit into
mainfrom
mstanbCO/add-invitation-account-type

Conversation

@mstanbCO

Copy link
Copy Markdown
Contributor

What

Adds a fourth value to UserTrait.AccountType in proto/c1/connector/v2/annotation_trait.proto:

ACCOUNT_TYPE_INVITATION = 4;

Connectors can now mark an account as a pending invitation — it exists in the source system and can hold grants, but no person or service is behind it until the invite is accepted — instead of forcing it into HUMAN, SERVICE, or SYSTEM.

Changes

  • proto/c1/connector/v2/annotation_trait.proto — new enum value with a comment describing its semantics.
  • pb/c1/connector/v2/annotation_trait{,_protoopaque}.pb.go — regenerated via buf generate.
  • pkg/types/resource/user_trait_test.go — test asserting WithAccountType(ACCOUNT_TYPE_INVITATION) survives NewUserTrait (the human default only applies to UNSPECIFIED) and passes ValidateAll under the defined_only enum rule.

No Go helper changes were needed: WithAccountType already takes the enum, and pkg/c1zsanitize copies the field verbatim.

Compatibility

Additive only — new enum number, nothing renumbered or removed. buf breaking --against main is clean. Consumers that switch on the enum will see ACCOUNT_TYPE_INVITATION fall through to their default branch until they handle it explicitly.

Verification

  • buf lint, buf format -w (no diff), buf breaking --against '.git#branch=main' — clean
  • go build ./...
  • go test ./pkg/types/resource/... ./pkg/c1zsanitize/... — pass
  • golangci-lint run pkg/types/resource/... — 0 issues

Lets connectors mark an account that exists in the source system as a
pending invitation rather than a real human or service account.

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
// An invitation to join the app that has not been accepted yet. The
// account exists in the source system and can hold grants, but no person
// or service is behind it until the invite is accepted.
ACCOUNT_TYPE_INVITATION = 4;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion (confidence: medium-high): The PR description says older consumers will see this value "fall through to their default branch," which understates the rollout constraint. account_type carries (validate.rules).enum = {defined_only: true}, and the generated validator looks up UserTrait_AccountType_name at runtime (pb/c1/connector/v2/annotation_trait.pb.validate.go:181) — so any reader still on a pre-this-PR SDK that calls UserTrait.Validate()/ValidateAll() will reject value 4 rather than default it, and older protojson readers using DiscardUnknown will silently coerce it to ACCOUNT_TYPE_UNSPECIFIED.

The change itself is correctly additive; the ask is just a rollout note in the PR/commit stating that platform and downstream readers must be on an SDK containing this enum value before any connector starts emitting it.

@github-actions

Copy link
Copy Markdown
Contributor

General PR Review: feat(proto): add ACCOUNT_TYPE_INVITATION to UserTrait.AccountType

Blocking Issues: 0 | Suggestions: 1 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base e2bd8af9aa92.
Review mode: full
View review run

Review Summary

Scanned the full PR diff for security and correctness. This is a purely additive proto enum addition (ACCOUNT_TYPE_INVITATION = 4) plus regenerated pb.go output and one test; nothing is renumbered, removed, or retyped, no go.mod/go.sum changes, and no security-relevant surface is touched. One non-blocking suggestion about rollout ordering for older readers.

Risk triage (per docs/BUG_CATCHING.md §2): silence — moderate (a misapplied account type is a well-formed wrong row, not a crash); durability — yes (the value persists into .c1z artifacts and crosses to the c1 platform); uncontrolled dimensions — yes, version-pair dependence between the SDK that writes the value and the SDK that reads it; consumer distance — the c1 platform and downstream connectors. Version-pair dependence pushes this to HIGH on escape, but the consequence sits at remediation rung 1–2 (redeploy readers / re-sync) and the change is the sanctioned additive shape, so no escalation to a full pass-set review is warranted. The review-blind class here is cross-version reads; the instrument would be a two-version round-trip check, which is not present in the diff and is not proportionate for a single additive enum value.

Verified during review:

  • Generated output is consistent with the source. Both annotation_trait.pb.go and annotation_trait_protoopaque.pb.go were regenerated, and the rawDesc length prefixes line up: the UserTrait message grows 1437 → 1467 bytes and the AccountType enum grows 118 → 147 bytes plus one byte for the widened varint prefix, exactly matching the 29-byte encoded enum value.
  • pb/c1/connector/v2/annotation_trait.pb.validate.go correctly needs no regeneration — the defined_only rule resolves against the runtime UserTrait_AccountType_name map, so value 4 validates. The new test's ValidateAll assertion confirms this.
  • No exhaustive switch on UserTrait_AccountType exists in the SDK. pkg/types/resource/user_trait.go:179 only rewrites UNSPECIFIEDHUMAN, so INVITATION survives NewUserTrait, and pkg/c1zsanitize/handlers.go:173 copies the field verbatim. Both claims in the PR description check out.
  • No other checked-in artifact (descriptor set, frontend, docs, SQL) enumerates these values, so there is no generated-artifact drift.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • proto/c1/connector/v2/annotation_trait.proto:51 — the stated compatibility behavior for older consumers is understated; under defined_only: true an older reader rejects value 4 rather than defaulting it. Worth a rollout-ordering note.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `proto/c1/connector/v2/annotation_trait.proto`:
- Around line 51: The new `ACCOUNT_TYPE_INVITATION = 4` enum value is additive and
  correct, but the PR description's compatibility claim ("consumers that switch on the
  enum will see ACCOUNT_TYPE_INVITATION fall through to their default branch") is not
  accurate for validating readers. The `account_type` field at line 53 carries
  `(validate.rules).enum = {defined_only: true}`, and the generated validator in
  `pb/c1/connector/v2/annotation_trait.pb.validate.go` (around line 181) checks
  membership in the runtime `UserTrait_AccountType_name` map. A consumer still running a
  pre-this-PR generated SDK will therefore return a `UserTraitValidationError` for
  account type 4 instead of falling through to a default branch. Separately, an older
  reader decoding protojson with `DiscardUnknown: true` (the pattern used in
  `pkg/lambda/grpc/transport.go`) will silently coerce the unknown enum name to
  `ACCOUNT_TYPE_UNSPECIFIED` rather than erroring. No code change is required; update the
  PR description and/or commit message with a rollout note stating that the c1 platform
  and any downstream readers must be running an SDK version that includes this enum value
  before connectors begin emitting `ACCOUNT_TYPE_INVITATION`.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant