Skip to content

Individual account approval resources (go) - #23

Open
lucasmiranda-stark wants to merge 1 commit into
masterfrom
feature/account-approval
Open

Individual account approval resources (go)#23
lucasmiranda-stark wants to merge 1 commit into
masterfrom
feature/account-approval

Conversation

@lucasmiranda-stark

Copy link
Copy Markdown
Contributor

Context

The account-approval feature — IndividualAccountRequest and IndividualAccountAttachment (each with a read-only .Log) — for the go infra SDK. Generated from contracts individual-account-request.md (v3) and individual-account-attachment.md (v3). Run-type: generate. Run artifacts: runs/20260528-182857-account-approval/go/.

What changed

  • Add IndividualAccountRequest (create/get/query/page/update + read-only .Log) with a structured Address sub-resource (nested object, never flattened).
  • Add IndividualAccountAttachment (create/get/query/page/cancel + read-only .Log); the constructor encodes content+contentType into a data:<contentType>;base64,… URL client-side; contentType is input-only.
  • CHANGELOG entry + per-resource README usage sections.

Test plan

  • 33 unit tests passing locally against the infra sandbox (Phase 6 — see runs/20260528-182857-account-approval/go/test-run-success.md)
  • Sandbox smoke check (manual after merge)

Risk & Rollback

  • Risk: new resources, additive only — no changes to existing public types.
  • Rollback: revert this PR; no data migration.

Contract review (Phase 7)

Contract Review

Run metadata

  • Run ID: 20260528-182857-account-approval
  • Language: go | Scope: infra | Run-type: generate
  • Round: 4
  • Contracts: contracts/individual-account-request.md (v3), contracts/individual-account-attachment.md (v3)

Checklist

IndividualAccountRequest (M1–M12)

Mandatory point Status Implementation Test
[M1] create accepts a list of IndividualAccountRequest and returns the same shape with server-assigned id, status, accountType, created, updated populated covered sdk-infra/go/starkinfra/individualaccountrequest/individual_account_request.go:52-71 TestIndividualAccountRequestPost @ sdk-infra/go/tests/sdk/individual_account_request_test.go:51-67
[M2] address is a nested object (not a string, not flattened) with all required sub-fields; serialized as nested JSON covered sdk-infra/go/starkinfra/individualaccountrequest/address.go:17-24 TestIndividualAccountRequestPostAddressIsObject @ sdk-infra/go/tests/sdk/individual_account_request_test.go:71-100
[M3] get(id) returns a single IndividualAccountRequest by id covered sdk-infra/go/starkinfra/individualaccountrequest/individual_account_request.go:73-93 TestIndividualAccountRequestInfoGet @ sdk-infra/go/tests/sdk/individual_account_request_test.go:159-201
[M4] query returns a channel of IndividualAccountRequest, accepting limit, after, before, status, tags, ids covered sdk-infra/go/starkinfra/individualaccountrequest/individual_account_request.go:95-133 TestIndividualAccountRequestQuery @ sdk-infra/go/tests/sdk/individual_account_request_test.go:104-129
[M5] page returns ([]IndividualAccountRequest, cursor, err) and accepts the same params as query plus cursor covered sdk-infra/go/starkinfra/individualaccountrequest/individual_account_request.go:135-162 TestIndividualAccountRequestPage @ sdk-infra/go/tests/sdk/individual_account_request_test.go:133-153
[M6] update(id, ...) PATCHes the request accepting any subset of name, taxId, address, income, status, tags; replaces address as a whole object covered sdk-infra/go/starkinfra/individualaccountrequest/individual_account_request.go:164-192 TestIndividualAccountRequestUpdate + TestIndividualAccountRequestUpdateAddressObject @ sdk-infra/go/tests/sdk/individual_account_request_test.go:206-297
[M7] status enum is exactly approved|created|denied|processing|updated (v1's success/failed/canceled not used); status-enum test asserts membership covered sdk-infra/go/starkinfra/individualaccountrequest/individual_account_request.go:43 (field present) TestIndividualAccountRequestInfoGet asserts assert.Contains(t, []string{"approved","created","denied","processing","updated"}, getRequest.Status) @ sdk-infra/go/tests/sdk/individual_account_request_test.go:196
[M8] IndividualAccountRequest.Log is read-only, exposed under individualaccountrequest/log, provides get, query, page; Log's request field is the parent type (not a string id) covered sdk-infra/go/starkinfra/individualaccountrequest/log/log.go:24-121 (Log struct with Request IndividualAccountRequest.IndividualAccountRequest at line 26) TestIndividualAccountRequestLogGet asserts getLog.Request.Id @ sdk-infra/go/tests/sdk/individual_account_request_log_test.go:87-128
[M9] Log.query and Log.page accept limit, after, before, types, accountRequestIds covered sdk-infra/go/starkinfra/individualaccountrequest/log/log.go:56-93 (Query), 95-121 (Page) — both accept types and accountRequestIds per docstring lines 66-68, 106-108 TestIndividualAccountRequestLogQuery uses params["types"] + params["accountRequestIds"] @ sdk-infra/go/tests/sdk/individual_account_request_log_test.go:40-42
[M10] created and updated are parsed to *time.Time (native datetime type); pattern matches existing SDK covered sdk-infra/go/starkinfra/individualaccountrequest/individual_account_request.go:46-47 (Created *time.Time, Updated *time.Time) TestIndividualAccountRequestInfoGet asserts assert.NotNil(t, getRequest.Created) @ sdk-infra/go/tests/sdk/individual_account_request_test.go:198
[M11] accountType, flags, id, status, created, updated are output-only (declared in struct; ignored by API on POST) covered sdk-infra/go/starkinfra/individualaccountrequest/individual_account_request.go:36-47 (all output-only fields present in struct) TestIndividualAccountRequestPost asserts assert.Equal(t, "individual", request.AccountType) @ sdk-infra/go/tests/sdk/individual_account_request_test.go:65
[M12] Each of the 6 error cases (name empty, taxId invalid, address missing sub-fields, income < 0, status invalid transition, unknown id) has a test that asserts InputErrors type raised — code-agnostic (non-nil err.Errors) covered sdk-infra/go/starkinfra/individualaccountrequest/individual_account_request.go:52-71 (Create), 73-93 (Get), 164-192 (Update) — all propagate Error.StarkErrors TestIndividualAccountRequestPostInvalidName (line 308), TestIndividualAccountRequestPostInvalidTaxId (line 321), TestIndividualAccountRequestPostInvalidAddress (line 334), TestIndividualAccountRequestPostInvalidIncome (line 349), TestIndividualAccountRequestUpdateInvalidStatus (line 363), TestIndividualAccountRequestGetNotFound (line 399) @ sdk-infra/go/tests/sdk/individual_account_request_test.go — all assert err.Errors != nil only

IndividualAccountAttachment (M1–M14)

Mandatory point Status Implementation Test
[M1] create accepts a list of IndividualAccountAttachment and returns the same shape with server-assigned id, status, created populated covered sdk-infra/go/starkinfra/individualaccountattachment/individual_account_attachment.go:46-74 TestIndividualAccountAttachmentPost @ sdk-infra/go/tests/sdk/individual_account_attachment_test.go:62-77
[M2] Constructor encodes content + contentType into data:<contentType>;base64,<payload> URL client-side before serialization covered sdk-infra/go/starkinfra/individualaccountattachment/individual_account_attachment.go:62-66 (fmt.Sprintf("data:%s;base64,%s", ...)) TestIndividualAccountAttachmentPostEncodesDataUrl asserts strings.HasPrefix(attachments[0].Content, "data:image/png;base64,") @ sdk-infra/go/tests/sdk/individual_account_attachment_test.go:83-104
[M3] contentType is input-only: after constructor builds the data URL, contentType is blanked and never sent as its own wire field covered sdk-infra/go/starkinfra/individualaccountattachment/individual_account_attachment.go:65 (attachments[i].ContentType = "") TestIndividualAccountAttachmentPostEncodesDataUrl asserts assert.Equal(t, "", attachments[0].ContentType) @ sdk-infra/go/tests/sdk/individual_account_attachment_test.go:103
[M4] get(id) returns a single IndividualAccountAttachment by id covered sdk-infra/go/starkinfra/individualaccountattachment/individual_account_attachment.go:76-96 TestIndividualAccountAttachmentInfoGet @ sdk-infra/go/tests/sdk/individual_account_attachment_test.go:173-214
[M5] query returns a channel of IndividualAccountAttachment, accepting limit, after, before, status, tags, ids covered sdk-infra/go/starkinfra/individualaccountattachment/individual_account_attachment.go:98-136 TestIndividualAccountAttachmentQuery @ sdk-infra/go/tests/sdk/individual_account_attachment_test.go:121-146
[M6] page returns ([]IndividualAccountAttachment, cursor, err) and accepts the same params as query plus cursor covered sdk-infra/go/starkinfra/individualaccountattachment/individual_account_attachment.go:138-165 TestIndividualAccountAttachmentPage @ sdk-infra/go/tests/sdk/individual_account_attachment_test.go:149-169
[M7] cancel(id) maps to DELETE and returns resource with status = "deleted" (not "canceled"); cancel is idempotent — second cancel succeeds covered sdk-infra/go/starkinfra/individualaccountattachment/individual_account_attachment.go:167-189 (utils.Delete) TestIndividualAccountAttachmentCancel asserts assert.Equal(t, "deleted", canceled.Status) @ line 240; TestIndividualAccountAttachmentCancelIdempotent asserts second cancel succeeds @ sdk-infra/go/tests/sdk/individual_account_attachment_test.go:246-273
[M8] Resource is exposed under individualaccountattachment (not accountrequestattachment) covered sdk-infra/go/starkinfra/individualaccountattachment/individual_account_attachment.go:1 (package individualaccountattachment) sdk-infra/go/tests/sdk/individual_account_attachment_test.go:53 (imports individualaccountattachment)
[M9] IndividualAccountAttachment.Log is read-only, exposed under individualaccountattachment/log, provides get, query, page; Log's attachment field is the parent type (not a string id) covered sdk-infra/go/starkinfra/individualaccountattachment/log/log.go:24-121 (Log struct with Attachment IndividualAccountAttachment.IndividualAccountAttachment at line 26) TestIndividualAccountAttachmentLogGet asserts getLog.Attachment.Id @ sdk-infra/go/tests/sdk/individual_account_attachment_log_test.go:128
[M10] Log.query and Log.page accept limit, after, before, types, attachmentIds (not accountRequestIds) covered sdk-infra/go/starkinfra/individualaccountattachment/log/log.go:56-93 (Query), 95-121 (Page) — both accept attachmentIds per docstring lines 67, 108 TestIndividualAccountAttachmentLogQuery uses params["attachmentIds"] @ sdk-infra/go/tests/sdk/individual_account_attachment_log_test.go:44-45; TestIndividualAccountAttachmentLogPage uses params["attachmentIds"] @ line 74
[M11] type enum is exactly drivers-license-front|drivers-license-back|identity-front|identity-back; no selfie covered fixture at sdk-infra/go/tests/utils/generator/example_generator.go:582 uses "identity-front" (no selfie) TestIndividualAccountAttachmentPostTypeEnum asserts assert.Contains(t, validTypes, attachment.Type) where validTypes excludes "selfie" @ sdk-infra/go/tests/sdk/individual_account_attachment_test.go:108-118
[M12] created is parsed to *time.Time (native datetime type) covered sdk-infra/go/starkinfra/individualaccountattachment/individual_account_attachment.go:41 (Created *time.Time) TestIndividualAccountAttachmentInfoGet asserts assert.NotNil(t, getAttachment.Created) @ sdk-infra/go/tests/sdk/individual_account_attachment_test.go:210
[M13] Each of the 5 error cases (type invalid, content empty, contentType missing, accountRequestId not found, unknown id) has a test asserting InputErrors type raised — code-agnostic; each attachment error test creates a fresh parent request covered sdk-infra/go/starkinfra/individualaccountattachment/individual_account_attachment.go:46-74 (Create), 76-96 (Get) — propagate Error.StarkErrors TestIndividualAccountAttachmentPostInvalidType (line 288), TestIndividualAccountAttachmentPostInvalidContent (line 299), TestIndividualAccountAttachmentPostInvalidContentType (line 311), TestIndividualAccountAttachmentPostNotFoundParent (line 325), TestIndividualAccountAttachmentGetNotFound (line 339) @ sdk-infra/go/tests/sdk/individual_account_attachment_test.go — all assert err.Errors != nil only; fixture Example.IndividualAccountAttachment() provisions a fresh parent per call (example_generator.go:562-589)
[M14] Previous AccountRequestAttachment resource (route /account-request-attachment, SDK identifier accountRequestAttachment) is removed in the same change set — no dual exposure not applicable n/a — grep of sdk-infra/go/starkinfra/ confirms no accountrequestattachment package has ever existed (grep returned 0 results for accountRequestAttachment|account-request-attachment in src); this is a generate run — there is no legacy resource to remove. Test comment at individual_account_attachment_test.go:26-28 explicitly records this verification. n/a — no legacy tests existed to delete

Summary

  • Total mandatory points: 26 (IndividualAccountRequest M1–M12 = 12; IndividualAccountAttachment M1–M14 = 14)
  • covered: 25
  • not covered: 0
  • partial: 0
  • not applicable: 1 (Attachment M14 — legacy resource never existed in sdk-infra/go)
  • VERDICT: PASS (not-covered == 0 and partial == 0)

Advisory notes (not blocking — route to Phase 5 / pattern-reviewer if not already flagged)

These are docstring/comment inaccuracies in the scaffold. They do not affect runtime behavior and are not Phase 7 blocking items, but should be addressed:

  1. Stale status enum in IndividualAccountRequest scaffold docstring: individual_account_request.go:15,30,105,147 still reference "success" | "failed" | "canceled" (v1 values). The v3 contract enum is approved | created | denied | processing | updated. The struct and test are correct; only the doc comment is stale.

  2. Stale type/status enum in IndividualAccountAttachment scaffold docstring: individual_account_attachment.go:20,30 include "selfie" in the type enum (contract explicitly excludes it) and list "canceled" as a status value (contract uses "deleted"). The Cancel docstring at lines 171–172,181 says "canceled" instead of "deleted". Implementation behavior (utils.Delete) and tests are correct.

  3. Stale log type enum in request/attachment log scaffold docstrings: log/log.go:20-21,66,107 (request log) and log/log.go:20-21,66,107 (attachment log) reference "success", "failed", "canceled" — v1 values. Tests use "created" (valid v3 value).

  4. Income field json:",omitempty" on int: individual_account_request.go:40 — Go's omitempty omits integer fields with value 0. The contract states income=0 is accepted. A caller passing Income: 0 would have that field silently dropped from the JSON body. No test exercises this path (not an M-point violation, but worth noting for correctness).

Metadata

  • Contracts: contracts/individual-account-request.md (v3), contracts/individual-account-attachment.md (v3)
  • Run artifacts: runs/20260528-182857-account-approval/go/
  • Branch: feature/account-approval
  • Base SHA: 89c7d3bac711035fc408ee04283fabd9edee8faa

@lucasmiranda-stark
lucasmiranda-stark requested a review from a team May 29, 2026 16:13
@lucasmiranda-stark
lucasmiranda-stark force-pushed the feature/account-approval branch from bc555fe to faf6984 Compare May 29, 2026 23:49
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